Compare commits

..

2 Commits

Author SHA1 Message Date
Jon Häggblad c87410dbdd Fix variable name 2024-09-23 16:02:54 +02:00
Jon Häggblad ed8c700d00 Extendd UserAgent with system information collected at runtime 2024-09-23 11:08:49 +02:00
1098 changed files with 20545 additions and 64308 deletions
+22 -1
View File
@@ -5,7 +5,7 @@ on:
jobs:
build:
runs-on: arc-ubuntu-20.04
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- name: Install Dependencies (Linux)
@@ -99,3 +99,24 @@ jobs:
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
working-directory: dist/docs
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
on:
workflow_dispatch:
pull_request:
paths:
- "ts-packages/**"
@@ -10,7 +9,7 @@ on:
jobs:
build:
runs-on: arc-ubuntu-20.04
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- name: Install rsync
@@ -46,3 +45,23 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
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
@@ -26,7 +26,6 @@ on:
- "nym-api/**"
- "nym-node/**"
- "nym-outfox/**"
- 'nym-data-observatory/**'
- "nym-validator-rewarder/**"
- "sdk/rust/nym-sdk/**"
- "service-providers/**"
@@ -97,7 +96,6 @@ jobs:
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-data-observatory
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
@@ -115,7 +113,6 @@ jobs:
cp target/release/nym-socks5-client $OUTPUT_DIR
cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-data-observatory $OUTPUT_DIR
cp target/release/nymvisor $OUTPUT_DIR
cp target/release/nym-node $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
@@ -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 -8
View File
@@ -16,7 +16,6 @@ on:
- 'nym-api/**'
- 'nym-node/**'
- 'nym-outfox/**'
- 'nym-data-observatory/**'
- 'nym-validator-rewarder/**'
- 'tools/**'
- 'wasm/**'
@@ -30,7 +29,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ]
os: [arc-ubuntu-20.04, custom-runner-mac-m1]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
@@ -57,17 +56,19 @@ jobs:
command: fmt
args: --all -- --check
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
# while disabled by default, this build ensures nothing is broken within
# `axum` feature
- name: Build with `axum` feature
uses: actions-rs/cargo@v1
with:
command: build
args: --features axum
- name: Build all examples
if: contains(matrix.os, 'ubuntu')
uses: actions-rs/cargo@v1
@@ -88,3 +89,9 @@ jobs:
with:
command: test
args: --workspace -- --ignored
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets --features axum -- -D warnings
+1 -1
View File
@@ -22,4 +22,4 @@ jobs:
with:
log-level: warn
command: check ${{ matrix.checks }}
arguments: --all-features
argument: --all-features
@@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [ arc-ubuntu-20.04 ]
platform: arc-ubuntu-20.04
runs-on: ${{ matrix.platform }}
env:
+22 -1
View File
@@ -10,7 +10,7 @@ on:
jobs:
build:
runs-on: arc-ubuntu-20.04
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- name: Install Dependencies (Linux)
@@ -70,3 +70,24 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
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
on:
workflow_dispatch:
pull_request:
paths:
- "ts-packages/**"
@@ -15,7 +14,7 @@ on:
jobs:
build:
runs-on: arc-ubuntu-20.04
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- uses: rlespinasse/github-slug-action@v3.x
@@ -54,3 +53,24 @@ jobs:
run: yarn lint
- name: Typecheck with 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:
publish:
runs-on: arc-ubuntu-20.04
runs-on: ubuntu-20.04-16-core
steps:
- 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
-150
View File
@@ -4,156 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.12-aero] (2024-10-17)
- nym-node: don't use bloomfilters for double spending checks ([#4960])
- bugfix: replace unreachable macro with an error return ([#4958])
- [DOCs:/operators]: Update FAQ sphinx size ([#4946])
- [DOCs/operators]: Release notes v2024.11-wedel ([#4939])
- Fix handle drop ([#4934])
- Assume offline mode ([#4926])
- Make ip-packet-request VERSION pub ([#4925])
- Expose error type ([#4924])
- Fix argument to cargo-deny action ([#4922])
- Fix nymvpn.com url in mainnet defaults ([#4920])
- Check both version and type in message header ([#4918])
- Bump http-api-client default timeout to 30 sec ([#4917])
- Max/proxy ffi ([#4906])
- Data Observatory stub ([#4905])
- Fix missing duplication of modified tables ([#4904])
- Update cargo deny ([#4901])
- docs: add hostname instructions for wss ([#4900])
- build(deps): bump the patch-updates group across 1 directory with 9 updates ([#4898])
- Fix clippy for beta toolchain ([#4897])
- Remove clippy github PR annotations ([#4896])
- Fix apt install in ci-build-upload-binaries.yml ([#4894])
- Update network monitor entrypoint ([#4893])
- Update nym-vpn metapackage and replace nymvpn-x with nym-vpn-app ([#4889])
- Entry wireguard tickets ([#4888])
- Build and Push CI ([#4887])
- Feature/updated gateway registration ([#4885])
- Few fixes to NNM pre deploy ([#4883])
- Fix sql serde with enum ([#4875])
- allow clients to send stateless gateway requests without prior registration ([#4873])
- chore: remove queued migration for adding explicit admin ([#4871])
- Gateway database modifications for different modes ([#4868])
- build(deps): bump strum from 0.25.0 to 0.26.3 ([#4848])
- Use serde from workspace ([#4833])
- build(deps): bump toml from 0.5.11 to 0.8.14 ([#4805])
- Max/rust sdk stream abstraction ([#4743])
[#4960]: https://github.com/nymtech/nym/pull/4960
[#4958]: https://github.com/nymtech/nym/pull/4958
[#4946]: https://github.com/nymtech/nym/pull/4946
[#4939]: https://github.com/nymtech/nym/pull/4939
[#4934]: https://github.com/nymtech/nym/pull/4934
[#4926]: https://github.com/nymtech/nym/pull/4926
[#4925]: https://github.com/nymtech/nym/pull/4925
[#4924]: https://github.com/nymtech/nym/pull/4924
[#4922]: https://github.com/nymtech/nym/pull/4922
[#4920]: https://github.com/nymtech/nym/pull/4920
[#4918]: https://github.com/nymtech/nym/pull/4918
[#4917]: https://github.com/nymtech/nym/pull/4917
[#4906]: https://github.com/nymtech/nym/pull/4906
[#4905]: https://github.com/nymtech/nym/pull/4905
[#4904]: https://github.com/nymtech/nym/pull/4904
[#4901]: https://github.com/nymtech/nym/pull/4901
[#4900]: https://github.com/nymtech/nym/pull/4900
[#4898]: https://github.com/nymtech/nym/pull/4898
[#4897]: https://github.com/nymtech/nym/pull/4897
[#4896]: https://github.com/nymtech/nym/pull/4896
[#4894]: https://github.com/nymtech/nym/pull/4894
[#4893]: https://github.com/nymtech/nym/pull/4893
[#4889]: https://github.com/nymtech/nym/pull/4889
[#4888]: https://github.com/nymtech/nym/pull/4888
[#4887]: https://github.com/nymtech/nym/pull/4887
[#4885]: https://github.com/nymtech/nym/pull/4885
[#4883]: https://github.com/nymtech/nym/pull/4883
[#4875]: https://github.com/nymtech/nym/pull/4875
[#4873]: https://github.com/nymtech/nym/pull/4873
[#4871]: https://github.com/nymtech/nym/pull/4871
[#4868]: https://github.com/nymtech/nym/pull/4868
[#4848]: https://github.com/nymtech/nym/pull/4848
[#4833]: https://github.com/nymtech/nym/pull/4833
[#4805]: https://github.com/nymtech/nym/pull/4805
[#4743]: https://github.com/nymtech/nym/pull/4743
## [2024.11-wedel] (2024-09-23)
- Backport #4894 to fix ci ([#4899])
- Bugfix/ticketbook false double spending ([#4892])
- fix: allow updating globally stored signatures ([#4891])
- [DOCs/operators]: Document changelog for patch/2024.10-caramello ([#4886])
- [DOCs/operators]: Post release docs updates ([#4874])
- Bump defguard to github latest version ([#4872])
- chore: removed completed queued mixnet migration ([#4865])
- Disable push trigger and add missing paths in ci-build ([#4864])
- Fix linux conditional in ci-build.yml ([#4863])
- Remove golang workaround in ci-sdk-wasm ([#4858])
- Revert runner for ci-docs ([#4855])
- Move credential verification into common crate ([#4853])
- Fix test failure in ipr request size ([#4844])
- Start switching over jobs to arc-ubuntu-20.04 ([#4843])
- Use ecash credential type for bandwidth value ([#4840])
- Create nym-repo-setup debian package and nym-vpn meta package ([#4837])
- Remove serde_crate named import ([#4832])
- Run cargo autoinherit following last weeks dependabot updates ([#4831])
- revamped ticketbook serialisation and exposed additional cli methods ([#4827])
- Expose wireguard details on self described endpoint ([#4825])
- Remove unused wireguard flag from SDK ([#4823])
- Add `axum` server to `nym-api` ([#4803])
- Run cargo-autoinherit for a few new crates ([#4801])
- Update dependabot ([#4796])
- Fix clippy for unwrap_or_default ([#4783])
- Enable dependabot version upgrades for root rust workspace ([#4778])
- Persist used wireguard private IPs ([#4771])
- Avoid race on ip and registration structures ([#4766])
- docs/hotfix ([#4765])
- chore: remove repetitive words ([#4763])
- Make gateway latency check generic ([#4759])
- Remove duplicate stat count for retransmissions ([#4756])
- Update peer refresh value ([#4754])
- Remove deprecated mark_as_success and use new disarm ([#4751])
- Add get_mixnodes_described to validator_client ([#4725])
- New Network Monitor ([#4610])
[#4899]: https://github.com/nymtech/nym/pull/4899
[#4892]: https://github.com/nymtech/nym/pull/4892
[#4891]: https://github.com/nymtech/nym/pull/4891
[#4886]: https://github.com/nymtech/nym/pull/4886
[#4874]: https://github.com/nymtech/nym/pull/4874
[#4872]: https://github.com/nymtech/nym/pull/4872
[#4865]: https://github.com/nymtech/nym/pull/4865
[#4864]: https://github.com/nymtech/nym/pull/4864
[#4863]: https://github.com/nymtech/nym/pull/4863
[#4858]: https://github.com/nymtech/nym/pull/4858
[#4855]: https://github.com/nymtech/nym/pull/4855
[#4853]: https://github.com/nymtech/nym/pull/4853
[#4844]: https://github.com/nymtech/nym/pull/4844
[#4843]: https://github.com/nymtech/nym/pull/4843
[#4840]: https://github.com/nymtech/nym/pull/4840
[#4837]: https://github.com/nymtech/nym/pull/4837
[#4832]: https://github.com/nymtech/nym/pull/4832
[#4831]: https://github.com/nymtech/nym/pull/4831
[#4827]: https://github.com/nymtech/nym/pull/4827
[#4825]: https://github.com/nymtech/nym/pull/4825
[#4823]: https://github.com/nymtech/nym/pull/4823
[#4803]: https://github.com/nymtech/nym/pull/4803
[#4801]: https://github.com/nymtech/nym/pull/4801
[#4796]: https://github.com/nymtech/nym/pull/4796
[#4783]: https://github.com/nymtech/nym/pull/4783
[#4778]: https://github.com/nymtech/nym/pull/4778
[#4771]: https://github.com/nymtech/nym/pull/4771
[#4766]: https://github.com/nymtech/nym/pull/4766
[#4765]: https://github.com/nymtech/nym/pull/4765
[#4763]: https://github.com/nymtech/nym/pull/4763
[#4759]: https://github.com/nymtech/nym/pull/4759
[#4756]: https://github.com/nymtech/nym/pull/4756
[#4754]: https://github.com/nymtech/nym/pull/4754
[#4751]: https://github.com/nymtech/nym/pull/4751
[#4725]: https://github.com/nymtech/nym/pull/4725
[#4610]: https://github.com/nymtech/nym/pull/4610
## [2024.10-caramello] (2024-09-10)
- Backport 4844 and 4845 ([#4857])
Generated
+684 -2010
View File
File diff suppressed because it is too large Load Diff
+18 -52
View File
@@ -54,14 +54,12 @@ members = [
"common/exit-policy",
"common/gateway-requests",
"common/gateway-storage",
"common/gateway-stats-storage",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
"common/ip-packet-requests",
"common/ledger",
"common/mixnode-common",
"common/models",
"common/network-defaults",
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
@@ -83,11 +81,9 @@ members = [
"common/nyxd-scraper",
"common/pemstore",
"common/serde-helpers",
"common/service-provider-requests-common",
"common/socks5-client-core",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/store-cipher",
"common/task",
"common/topology",
@@ -106,9 +102,6 @@ members = [
"mixnode",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"sdk/ffi/shared",
"sdk/ffi/go",
"sdk/ffi/cpp",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
@@ -117,15 +110,11 @@ members = [
"nym-api",
"nym-browser-extension/storage",
"nym-api/nym-api-requests",
"nym-data-observatory",
"nym-node",
"nym-node/nym-node-http-api",
"nym-node/nym-node-requests",
"nym-node-status-api",
"nym-node-status-agent",
"nym-outfox",
"nym-validator-rewarder",
"tools/echo-server",
"tools/internal/ssl-inject",
# "tools/internal/sdk-version-bump",
"tools/internal/testnet-manager",
@@ -140,26 +129,17 @@ members = [
"wasm/mix-fetch",
"wasm/node-tester",
"wasm/zknym-lib",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"tools/echo-server",
"tools/internal/contract-state-importer/importer-cli",
"tools/internal/contract-state-importer/importer-contract",
]
default-members = [
"clients/native",
"clients/socks5",
"common/models",
"explorer-api",
"gateway",
"mixnode",
"nym-api",
"nym-data-observatory",
"nym-node",
"nym-node-status-api",
"nym-validator-rewarder",
"nym-node-status-api",
"service-providers/authenticator",
"service-providers/ip-packet-router",
"service-providers/network-requester",
@@ -172,6 +152,7 @@ exclude = [
"nym-wallet",
"nym-vpn/ui/src-tauri",
"cpu-cycles",
"sdk/ffi/cpp",
]
[workspace.package]
@@ -190,11 +171,11 @@ aes = "0.8.1"
aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1"
aead = "0.5.2"
anyhow = "1.0.90"
anyhow = "1.0.89"
argon2 = "0.5.0"
async-trait = "0.1.83"
async-trait = "0.1.82"
axum = "0.7.5"
axum-extra = "0.9.4"
axum-extra = "0.9.3"
base64 = "0.22.1"
bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] }
@@ -207,7 +188,7 @@ blake3 = "1.5.4"
bloomfilter = "1.0.14"
bs58 = "0.5.1"
bytecodec = "0.4.15"
bytes = "1.7.2"
bytes = "1.7.1"
cargo_metadata = "0.18.1"
celes = "2.4.0"
cfg-if = "1.0.0"
@@ -215,7 +196,7 @@ chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.31"
cipher = "0.4.3"
clap = "4.5.20"
clap = "4.5.17"
clap_complete = "4.5"
clap_complete_fig = "4.5"
colored = "2.0"
@@ -231,8 +212,7 @@ ctr = "0.9.1"
cupid = "0.6.1"
curve25519-dalek = "4.1"
dashmap = "5.5.3"
# We want https://github.com/DefGuard/wireguard-rs/pull/64 , but there's no crates.io release being pushed out anymore
defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs.git", rev = "v0.4.7" }
defguard_wireguard_rs = "0.4.2"
digest = "0.10.7"
dirs = "5.0"
doc-comment = "0.3"
@@ -240,12 +220,10 @@ dotenvy = "0.15.6"
ecdsa = "0.16"
ed25519-dalek = "2.1"
etherparse = "0.13.0"
envy = "0.4"
eyre = "0.6.9"
fastrand = "2.1.1"
flate2 = "1.0.34"
flate2 = "1.0.33"
futures = "0.3.28"
futures-util = "0.3"
generic-array = "0.14.7"
getrandom = "0.2.10"
getset = "0.1.3"
@@ -275,7 +253,6 @@ ledger-transport-hid = "0.10.0"
log = "0.4"
maxminddb = "0.23.0"
mime = "0.3.17"
moka = { version = "0.12", features = ["future"] }
nix = "0.27.1"
notify = "5.1.0"
okapi = "0.7.0"
@@ -285,8 +262,7 @@ opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.3"
pem = "0.8"
petgraph = "0.6.5"
pin-project = "1.1"
pin-project-lite = "0.2.14"
pin-project = "1.0"
pretty_env_logger = "0.4.0"
publicsuffix = "2.2.3"
quote = "1"
@@ -305,27 +281,25 @@ rocket_okapi = "0.8.0"
safer-ffi = "0.1.13"
schemars = "0.8.21"
semver = "1.0.23"
serde = "1.0.211"
serde = "1.0.210"
serde_bytes = "0.11.15"
serde_derive = "1.0"
serde_json = "1.0.132"
serde_json_path = "0.6.7"
serde_json = "1.0.128"
serde_repr = "0.1"
serde_with = "3.9.0"
serde_yaml = "0.9.25"
sha2 = "0.10.8"
si-scale = "0.2.3"
sphinx-packet = "0.1.1"
sqlx = "0.7.4"
sqlx = "0.6.3"
strum = "0.26"
strum_macros = "0.26"
subtle-encoding = "0.5"
syn = "1"
sysinfo = "0.30.13"
tap = "1.0.1"
tar = "0.4.42"
tar = "0.4.41"
tempfile = "3.5.0"
thiserror = "1.0.64"
thiserror = "1.0.63"
time = "0.3.30"
tokio = "1.39"
tokio-stream = "0.1.16"
@@ -340,8 +314,7 @@ tracing = "0.1.37"
tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2"
tracing-log = "0.2"
ts-rs = "10.0.0"
ts-rs = "7.0.0"
tungstenite = { version = "0.20.1", default-features = false }
url = "2.5"
utoipa = "4.2"
@@ -363,7 +336,6 @@ prometheus = { version = "0.13.0" }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.0", default-features = false }
subtle = "2.5.0"
# cosmwasm-related
cosmwasm-schema = "=1.4.3"
@@ -402,20 +374,14 @@ indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", bra
js-sys = "0.3.70"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.95"
wasm-bindgen-futures = "0.4.45"
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.43"
wasmtimer = "0.2.0"
web-sys = "0.3.72"
web-sys = "0.3.70"
# Profile settings for individual crates
# Compile-time verified queries do quite a bit of work at compile time. Incremental
# actions like cargo check and cargo build can be significantly faster when
# using an optimized build
[profile.dev.package.sqlx-macros]
opt-level = 3
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.42"
version = "1.1.40"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.42"
version = "1.1.40"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
-15
View File
@@ -9,24 +9,9 @@ edition.workspace = true
license.workspace = true
[dependencies]
base64 = { workspace = true }
bincode = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
nym-service-provider-requests-common = { path = "../service-provider-requests-common" }
nym-sphinx = { path = "../nymsphinx" }
nym-wireguard-types = { path = "../wireguard-types" }
## verify:
hmac = { workspace = true, optional = true }
sha2 = { workspace = true, optional = true }
x25519-dalek = { workspace = true, features = ["static_secrets"] }
[features]
default = ["verify"]
# this is moved to a separate feature as we really need clients to import it (especially, *cough*, wasm)
verify = ["hmac", "sha2"]
@@ -1,25 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("the provided base64-encoded client MAC ('{mac}') was malformed: {source}")]
MalformedClientMac {
mac: String,
#[source]
source: base64::DecodeError,
},
#[cfg(feature = "verify")]
#[error("failed to verify mac provided by '{client}': {source}")]
FailedClientMacVerification {
client: String,
#[source]
source: hmac::digest::MacError,
},
#[error("conversion: {0}")]
Conversion(String),
}
+1 -8
View File
@@ -2,15 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub mod v2;
pub mod v3;
mod error;
pub use error::Error;
pub use v3 as latest;
pub const CURRENT_VERSION: u8 = 3;
pub const CURRENT_VERSION: u8 = 1;
fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options;
+1 -7
View File
@@ -1,13 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod registration;
pub mod request;
pub mod response;
pub use registration::{ClientMac, GatewayClient, InitMessage, Nonce};
#[cfg(feature = "verify")]
pub use registration::HmacSha256;
pub const VERSION: u8 = 1;
const VERSION: u8 = 1;
@@ -1,218 +0,0 @@
// Copyright 2023-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_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: i64 = 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 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: u64,
pub suspended: bool,
}
/// 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,9 +1,8 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{GatewayClient, InitMessage};
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use nym_wireguard_types::{GatewayClient, InitMessage, PeerPublicKey};
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
@@ -83,24 +82,3 @@ pub enum AuthenticatorRequestData {
Final(GatewayClient),
QueryBandwidth(PeerPublicKey),
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn check_first_byte_version() {
let version = 2;
let data = AuthenticatorRequest {
version,
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();
assert_eq!(*bytes.first().unwrap(), version);
}
}
@@ -1,8 +1,8 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
@@ -1,174 +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::{v1, v2};
impl From<v1::request::AuthenticatorRequest> for v2::request::AuthenticatorRequest {
fn from(authenticator_request: v1::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<v1::request::AuthenticatorRequestData> for v2::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v1::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
v1::request::AuthenticatorRequestData::Initial(init_msg) => {
v2::request::AuthenticatorRequestData::Initial(init_msg.into())
}
v1::request::AuthenticatorRequestData::Final(gw_client) => {
v2::request::AuthenticatorRequestData::Final(gw_client.into())
}
v1::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
}
}
}
}
impl From<v1::registration::InitMessage> for v2::registration::InitMessage {
fn from(init_msg: v1::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
}
}
impl From<v1::registration::GatewayClient> for Box<v2::registration::FinalMessage> {
fn from(gw_client: v1::registration::GatewayClient) -> Self {
Box::new(v2::registration::FinalMessage {
gateway_client: gw_client.into(),
credential: None,
})
}
}
impl From<v1::registration::GatewayClient> for v2::registration::GatewayClient {
fn from(gw_client: v1::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::GatewayClient> for v1::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<v1::registration::ClientMac> for v2::registration::ClientMac {
fn from(mac: v1::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v2::registration::ClientMac> for v1::registration::ClientMac {
fn from(mac: v2::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v2::response::AuthenticatorResponse> for v1::response::AuthenticatorResponse {
fn from(authenticator_response: v2::response::AuthenticatorResponse) -> Self {
Self {
version: authenticator_response.protocol.version,
data: authenticator_response.data.into(),
reply_to: authenticator_response.reply_to,
}
}
}
impl From<v2::response::AuthenticatorResponseData> for v1::response::AuthenticatorResponseData {
fn from(authenticator_response_data: v2::response::AuthenticatorResponseData) -> Self {
match authenticator_response_data {
v2::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response,
) => v1::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response.into(),
),
v2::response::AuthenticatorResponseData::Registered(registered_response) => {
v1::response::AuthenticatorResponseData::Registered(registered_response.into())
}
v2::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response,
) => v1::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response.into(),
),
}
}
}
impl From<v2::response::PendingRegistrationResponse> for v1::response::PendingRegistrationResponse {
fn from(value: v2::response::PendingRegistrationResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v2::response::RegisteredResponse> for v1::response::RegisteredResponse {
fn from(value: v2::response::RegisteredResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v2::response::RemainingBandwidthResponse> for v1::response::RemainingBandwidthResponse {
fn from(value: v2::response::RemainingBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.map(Into::into),
}
}
}
impl From<v2::registration::RegistrationData> for v1::registration::RegistrationData {
fn from(value: v2::registration::RegistrationData) -> Self {
Self {
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
}
impl From<v2::registration::RegistredData> for v1::registration::RegistredData {
fn from(value: v2::registration::RegistredData) -> Self {
Self {
pub_key: value.pub_key,
private_ip: value.private_ip,
wg_port: value.wg_port,
}
}
}
impl From<v2::registration::RemainingBandwidthData> for v1::registration::RemainingBandwidthData {
fn from(value: v2::registration::RemainingBandwidthData) -> Self {
Self {
available_bandwidth: value.available_bandwidth as u64,
suspended: false,
}
}
}
@@ -1,9 +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 const VERSION: u8 = 2;
@@ -1,227 +0,0 @@
// Copyright 2023-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,116 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{FinalMessage, InitMessage};
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 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),
}
#[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,129 +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 recipient(&self) -> Recipient {
self.reply_to
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
@@ -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,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_credentials::ecash::bandwidth::CredentialSpendingData;
use nym_credentials_interface::{
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, TicketType, VerificationKeyAuth,
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
};
use nym_ecash_time::Date;
use nym_validator_client::nym_api::EpochId;
@@ -64,10 +64,9 @@ impl<C, St: Storage> BandwidthController<C, St> {
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(
&self,
ticketbook_type: TicketType,
tickets: u32,
) -> Result<RetrievedTicketbook, BandwidthControllerError>
where
@@ -75,7 +74,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
{
let Some(ticketbook) = self
.storage
.get_next_unspent_usable_ticketbook(ticketbook_type.to_string(), tickets)
.get_next_unspent_usable_ticketbook(tickets)
.await
.map_err(BandwidthControllerError::credential_storage_error)?
else {
@@ -182,7 +181,6 @@ impl<C, St: Storage> BandwidthController<C, St> {
pub async fn prepare_ecash_ticket(
&self,
ticketbook_type: TicketType,
provider_pk: [u8; 32],
tickets_to_spend: u32,
) -> Result<PreparedCredential, BandwidthControllerError>
@@ -190,9 +188,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let retrieved_ticketbook = self
.get_next_usable_ticketbook(ticketbook_type, tickets_to_spend)
.await?;
let retrieved_ticketbook = self.get_next_usable_ticketbook(tickets_to_spend).await?;
let ticketbook_id = retrieved_ticketbook.ticketbook_id;
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
-1
View File
@@ -45,4 +45,3 @@ tracing = [
"opentelemetry",
]
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
models = []
@@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'",
"describe": {
"columns": [
{
"name": "exists",
"ordinal": 0,
"type_info": "Int"
}
],
"parameters": {
"Right": 1
},
"nullable": [
null
]
},
"hash": "06e743d143fcc4be20ca2af5e99b19f15d22fff72490473587a14cdc046fda32"
}
@@ -1,44 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT * FROM remote_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "gateway_owner_address",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "gateway_listener",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "derived_aes128_ctr_blake3_hmac_keys_bs58",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "derived_aes256_gcm_siv_key",
"ordinal": 4,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true,
false,
true,
true
]
},
"hash": "0e85ec18da67cf4e3df04ad80136571f6e920eb2290f20b1b8c5b0ab4b489985"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n UPDATE remote_gateway_details\n SET\n derived_aes128_ctr_blake3_hmac_keys_bs58 = ?,\n derived_aes256_gcm_siv_key = ?\n WHERE gateway_id_bs58 = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "0f1dfb89f1eb39f4a58787af0f53a7a93afb7e4d2e54e2d38fd79d31c8575a54"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "DELETE FROM remote_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "1da6904e72b5abb9abf75affb13af7974d7795b4cbdba234273345fe161df233"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "DELETE FROM custom_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "4f78619aca933484cd67cb89a376b2a5bec1c191993ff58f0c71c03e3ef6d92d"
}
@@ -1,26 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT * FROM custom_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "data",
"ordinal": 1,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true
]
},
"hash": "54f552a9dbe95236f946ac2b6615e03504afa58e345ae16a128629d8e76f0a11"
}
@@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT gateway_id_bs58 FROM registered_gateway",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false
]
},
"hash": "5661cf1ad8bd5ca062e855e1971a8787133ee41814bd3efdd501f9ee0c050f2b"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "UPDATE active_gateway SET active_gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "80476cf2906eb0ecf7f66c16bc5682169b87f488b6927fa67fade6bf5abf7582"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type) \n VALUES (?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "8909fd329e7e5fb16c4989b15b3d3a12bba1569520e01f6f074178e23d6ee89e"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, derived_aes256_gcm_siv_key, gateway_owner_address, gateway_listener)\n VALUES (?, ?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "a6939bea03b10cde810a9a099bd597b4f51092e30a41c4085a8f8668f039f7c0"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO custom_gateway_details(gateway_id_bs58, data) \n VALUES (?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "b059bc3688b6b7f83f47048db9897720fd4e6f3211bf74030a9638f7bf6738e4"
}
@@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT active_gateway_id_bs58 FROM active_gateway",
"describe": {
"columns": [
{
"name": "active_gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
true
]
},
"hash": "bf249752f08c283bf5942b6ff48125c24750b523cfcad1e5e9069dbf7050e2a1"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "DELETE FROM registered_gateway WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "f3ebe259e26c05ecdd33bd9085dbb91cd5046a8c9d4434cf085a4fa2ebf03e93"
}
@@ -29,10 +29,11 @@ impl StorageManager {
})?;
}
let opts = sqlx::sqlite::SqliteConnectOptions::new()
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(true)
.disable_statement_logging();
.create_if_missing(true);
opts.disable_statement_logging();
let connection_pool = sqlx::SqlitePool::connect_with(opts)
.await
@@ -81,7 +82,7 @@ impl StorageManager {
sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id)
.fetch_one(&self.connection_pool)
.await
.map(|result| result.exists == Some(1))
.map(|result| result.exists == 1)
}
pub(crate) async fn maybe_get_registered_gateway(
@@ -3,11 +3,11 @@ use log::{debug, error};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
nym_topology_from_basic_info,
nym_topology_from_detailed,
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
use nym_validator_client::client::NodeId;
use nym_validator_client::client::MixId;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;
use tap::TapOptional;
@@ -39,10 +39,10 @@ fn create_explorer_client() -> Option<ExplorerClient> {
fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<NodeId>> {
) -> HashMap<CountryGroup, Vec<MixId>> {
mixnodes
.into_iter()
.fold(HashMap::<CountryGroup, Vec<NodeId>>::new(), |mut acc, m| {
.fold(HashMap::<CountryGroup, Vec<MixId>>::new(), |mut acc, m| {
if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
@@ -53,7 +53,7 @@ fn group_mixnodes_by_country_code(
})
}
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<NodeId>>) {
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
let mixnode_distribution = mixnodes
.iter()
.map(|(k, v)| format!("{}: {}", k, v.len()))
@@ -110,11 +110,7 @@ impl GeoAwareTopologyProvider {
}
async fn get_topology(&self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
{
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
@@ -122,11 +118,7 @@ impl GeoAwareTopologyProvider {
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
let gateways = match self.validator_client.get_cached_gateways().await {
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
@@ -190,10 +182,11 @@ impl GeoAwareTopologyProvider {
let mixnodes = mixnodes
.into_iter()
.filter(|m| filtered_mixnode_ids.contains(&m.node_id))
.filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
.collect::<Vec<_>>();
let topology = nym_topology_from_basic_info(&mixnodes, &gateways);
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
// TODO: return real error type
check_layer_integrity(topology.clone()).ok()?;
@@ -98,7 +98,7 @@ impl NymApiTopologyProvider {
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.get_basic_mixnodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -110,7 +110,7 @@ impl NymApiTopologyProvider {
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.get_basic_gateways(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -134,6 +134,7 @@ impl NymApiTopologyProvider {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api();
+10
View File
@@ -187,6 +187,16 @@ pub enum ClientCoreError {
source: Ed25519RecoveryError,
},
#[error("the account owner of gateway {gateway_id} ({raw_owner}) is malformed: {err}")]
MalformedGatewayOwnerAccountAddress {
gateway_id: String,
raw_owner: String,
// just use the string formatting as opposed to underlying type to avoid having to import cosmrs
err: String,
},
#[error(
"the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}"
)]
+26 -19
View File
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_topology::{gateway, mix};
use nym_topology::{filter::VersionFilterable, gateway, mix};
use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng};
@@ -53,7 +53,7 @@ pub trait ConnectableGateway {
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for gateway::LegacyNode {
impl ConnectableGateway for gateway::Node {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
@@ -82,7 +82,7 @@ pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> {
) -> Result<Vec<gateway::Node>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -94,26 +94,31 @@ pub async fn current_gateways<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_all_basic_entry_assigned_nodes(None).await?;
let gateways = client.get_cached_described_gateways().await?;
log::debug!("Found {} gateways", gateways.len());
log::trace!("Gateways: {:#?}", gateways);
let valid_gateways = gateways
.iter()
.into_iter()
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::LegacyNode>>();
log::debug!("After checking validity: {}", valid_gateways.len());
.collect::<Vec<gateway::Node>>();
log::debug!("Ater checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {:#?}", valid_gateways);
log::info!("nym-api reports {} valid gateways", valid_gateways.len());
// we were always filtering by version so I'm not removing that 'feature'
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
log::debug!("After filtering for version: {}", filtered_gateways.len());
log::trace!("Filtered gateways: {:#?}", filtered_gateways);
Ok(valid_gateways)
log::info!("nym-api reports {} valid gateways", filtered_gateways.len());
Ok(filtered_gateways)
}
pub async fn current_mixnodes<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
) -> Result<Vec<mix::LegacyNode>, ClientCoreError> {
) -> Result<Vec<mix::Node>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -121,13 +126,15 @@ pub async fn current_mixnodes<R: Rng>(
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
.iter()
.filter_map(|mixnode| mixnode.try_into().ok())
.collect::<Vec<mix::LegacyNode>>();
.into_iter()
.filter_map(|mixnode| (&mixnode.bond_information).try_into().ok())
.collect::<Vec<mix::Node>>();
Ok(valid_mixnodes)
// we were always filtering by version so I'm not removing that 'feature'
let filtered_mixnodes = valid_mixnodes.filter_by_version(env!("CARGO_PKG_VERSION"));
Ok(filtered_mixnodes)
}
#[cfg(not(target_arch = "wasm32"))]
@@ -266,9 +273,9 @@ fn filter_by_tls<G: ConnectableGateway>(
pub(super) fn uniformly_random_gateway<R: Rng>(
rng: &mut R,
gateways: &[gateway::LegacyNode],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<gateway::LegacyNode, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
filter_by_tls(gateways, must_use_tls)?
.choose(rng)
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
@@ -277,9 +284,9 @@ pub(super) fn uniformly_random_gateway<R: Rng>(
pub(super) fn get_specified_gateway(
gateway_identity: IdentityKeyRef,
gateways: &[gateway::LegacyNode],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<gateway::LegacyNode, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
+1 -1
View File
@@ -50,7 +50,7 @@ async fn setup_new_gateway<K, D>(
key_store: &K,
details_store: &D,
selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<gateway::LegacyNode>,
available_gateways: Vec<gateway::Node>,
) -> Result<InitialisationResult, ClientCoreError>
where
K: KeyStore,
+18 -3
View File
@@ -18,6 +18,7 @@ use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId;
use serde::Serialize;
use std::fmt::Display;
use std::str::FromStr;
use std::sync::Arc;
use time::OffsetDateTime;
use url::Url;
@@ -38,7 +39,7 @@ pub enum SelectedGateway {
impl SelectedGateway {
pub fn from_topology_node(
node: gateway::LegacyNode,
node: gateway::Node,
must_use_tls: bool,
) -> Result<Self, ClientCoreError> {
let gateway_listener = if must_use_tls {
@@ -50,6 +51,20 @@ impl SelectedGateway {
node.clients_address()
};
let gateway_owner_address = node
.owner
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: raw_owner.clone(),
err: source.to_string(),
}
})
})
.transpose()?;
let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
gateway_id: node.identity_key.to_base58_string(),
@@ -59,7 +74,7 @@ impl SelectedGateway {
Ok(SelectedGateway::Remote {
gateway_id: node.identity_key,
gateway_owner_address: None,
gateway_owner_address,
gateway_listener,
})
}
@@ -200,7 +215,7 @@ pub enum GatewaySetup {
specification: GatewaySelectionSpecification,
// TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<gateway::LegacyNode>,
available_gateways: Vec<gateway::Node>,
},
ReuseConnection {
@@ -1,12 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::backend::fs_backend::{
error::StorageError,
models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag,
StoredSurbSender,
},
use crate::backend::fs_backend::error::StorageError;
use crate::backend::fs_backend::models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
};
use log::{error, info};
use sqlx::ConnectOptions;
@@ -30,10 +27,11 @@ impl StorageManager {
})?;
}
let opts = sqlx::sqlite::SqliteConnectOptions::new()
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(fresh)
.disable_statement_logging();
.create_if_missing(fresh);
opts.disable_statement_logging();
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
Ok(pool) => pool,
@@ -24,7 +24,6 @@ zeroize.workspace = true
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
nym-credentials = { path = "../../credentials" }
nym-credential-storage = { path = "../../credential-storage" }
nym-credentials-interface = { path = "../../credentials-interface" }
nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../gateway-requests" }
nym-network-defaults = { path = "../../network-defaults" }
@@ -2,37 +2,21 @@
// SPDX-License-Identifier: Apache-2.0
use si_scale::helpers::bibytes2;
use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use std::time::Duration;
use time::OffsetDateTime;
pub(crate) struct BandwidthClaimGuard {
inner: Arc<ClientBandwidthInner>,
}
impl Drop for BandwidthClaimGuard {
fn drop(&mut self) {
let old = self.inner.claiming_more.swap(false, Ordering::SeqCst);
assert!(
old,
"critical failure: there were multiple BandwidthClaimGuard existing"
)
}
}
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct ClientBandwidth {
inner: Arc<ClientBandwidthInner>,
}
#[derive(Default)]
struct ClientBandwidthInner {
/// the actual bandwidth amount (in bytes) available
available: AtomicI64,
/// flag to indicate whether this client is currently in the process of claiming additional bandwidth
claiming_more: AtomicBool,
/// defines the timestamp when the bandwidth information has been logged to the logs stream
last_logged_ts: AtomicI64,
@@ -45,28 +29,11 @@ impl ClientBandwidth {
ClientBandwidth {
inner: Arc::new(ClientBandwidthInner {
available: AtomicI64::new(0),
claiming_more: AtomicBool::new(false),
last_logged_ts: AtomicI64::new(0),
last_updated_ts: AtomicI64::new(0),
}),
}
}
pub(crate) fn begin_bandwidth_claim(&self) -> Option<BandwidthClaimGuard> {
if self
.inner
.claiming_more
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
Some(BandwidthClaimGuard {
inner: self.inner.clone(),
})
} else {
None
}
}
pub(crate) fn remaining(&self) -> i64 {
self.inner.available.load(Ordering::Acquire)
}
@@ -16,7 +16,6 @@ use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use nym_gateway_requests::registration::handshake::client_handshake;
use nym_gateway_requests::{
@@ -725,11 +724,6 @@ impl<C, St> GatewayClient<C, St> {
return Err(GatewayClientError::NoBandwidthControllerAvailable);
}
let Some(_claim_guard) = self.bandwidth.begin_bandwidth_claim() else {
debug!("there's already an existing bandwidth claim ongoing");
return Ok(());
};
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
if !self.cfg.bandwidth.require_tickets {
info!("The client is running in disabled credentials mode - attempting to claim bandwidth without a credential");
@@ -749,11 +743,7 @@ impl<C, St> GatewayClient<C, St> {
}
let prepared_credential = self
.unchecked_bandwidth_controller()
.prepare_ecash_ticket(
TicketType::V1MixnetEntry,
self.gateway_identity.to_bytes(),
TICKETS_TO_SPEND,
)
.prepare_ecash_ticket(self.gateway_identity.to_bytes(), TICKETS_TO_SPEND)
.await?;
match self.claim_ecash_bandwidth(prepared_credential.data).await {
@@ -20,12 +20,11 @@ nym-coconut-bandwidth-contract-common = { path = "../../cosmwasm-smart-contracts
nym-ecash-contract-common = { path = "../../cosmwasm-smart-contracts/ecash-contract" }
nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
nym-serde-helpers = { path = "../../serde-helpers", features = ["hex", "base64"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" }
thiserror = { workspace = true }
tracing = { workspace = true }
log = { workspace = true }
url = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["sync", "time"] }
time = { workspace = true, features = ["formatting"] }
@@ -17,11 +17,11 @@ use nym_api_requests::ecash::{
BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse,
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
};
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_coconut_dkg_common::types::EpochId;
use nym_http_api_client::UserAgent;
@@ -31,7 +31,7 @@ use url::Url;
pub use crate::nym_api::NymApiClientExt;
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
@@ -265,13 +265,6 @@ impl NymApiClient {
NymApiClient { nym_api }
}
#[cfg(not(target_arch = "wasm32"))]
pub fn new_with_timeout(api_url: Url, timeout: std::time::Duration) -> Self {
let nym_api = nym_api::Client::new(api_url, Some(timeout));
NymApiClient { nym_api }
}
pub fn new_with_user_agent(api_url: Url, user_agent: UserAgent) -> Self {
let nym_api = nym_api::Client::builder::<_, ValidatorClientError>(api_url)
.expect("invalid api url")
@@ -290,7 +283,6 @@ impl NymApiClient {
self.nym_api.change_base_url(new_endpoint);
}
#[deprecated(note = "use get_basic_active_mixing_assigned_nodes instead")]
pub async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
@@ -302,7 +294,6 @@ impl NymApiClient {
.nodes)
}
#[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
pub async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
@@ -314,70 +305,6 @@ impl NymApiClient {
.nodes)
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
pub async fn get_all_basic_entry_assigned_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_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(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
@@ -400,7 +327,7 @@ impl NymApiClient {
pub async fn get_cached_described_gateways(
&self,
) -> Result<Vec<LegacyDescribedGateway>, ValidatorClientError> {
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
Ok(self.nym_api.get_gateways_described().await?)
}
@@ -417,7 +344,7 @@ impl NymApiClient {
pub async fn get_mixnode_core_status_count(
&self,
mix_id: NodeId,
mix_id: MixId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
Ok(self
@@ -428,21 +355,21 @@ impl NymApiClient {
pub async fn get_mixnode_status(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_status(mix_id).await?)
}
pub async fn get_mixnode_reward_estimation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<RewardEstimationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?)
}
pub async fn get_mixnode_stake_saturation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<StakeSaturationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?)
}
@@ -121,36 +121,36 @@ async fn test_nyxd_connection(
{
Ok(Err(NyxdError::TendermintErrorRpc(e))) => {
// If we get a tendermint-rpc error, we classify the node as not contactable
tracing::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
log::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
false
}
Ok(Err(NyxdError::AbciError { code, log, .. })) => {
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
// for example on a pre-launch network.
tracing::debug!(
log::debug!(
"Checking: nyxd url: {url}: {}, but with abci error: {code}: {log}",
"success".green()
);
code == 18
}
Ok(Err(error @ NyxdError::NoContractAddressAvailable(_))) => {
tracing::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
log::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
false
}
Ok(Err(e)) => {
// For any other error, we're optimistic and just try anyway.
tracing::warn!(
log::warn!(
"Checking: nyxd_url: {url}: {}, but with error: {e}",
"success".green()
);
true
}
Ok(Ok(_)) => {
tracing::debug!("Checking: nyxd_url: {url}: {}", "success".green());
log::debug!("Checking: nyxd_url: {url}: {}", "success".green());
true
}
Err(e) => {
tracing::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
log::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
false
}
};
@@ -169,15 +169,15 @@ async fn test_nym_api_connection(
.await
{
Ok(Ok(_)) => {
tracing::debug!("Checking: api_url: {url}: {}", "success".green());
log::debug!("Checking: api_url: {url}: {}", "success".green());
true
}
Ok(Err(e)) => {
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false
}
Err(e) => {
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false
}
};
@@ -10,10 +10,8 @@ use nym_api_requests::ecash::models::{
VerifyEcashTicketBody,
};
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{
AnnotationResponse, LegacyDescribedMixNode, NodePerformanceResponse,
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
use nym_api_requests::models::DescribedMixNode;
use nym_api_requests::nym_nodes::{CachedNodesResponse, SkimmedNode};
pub use nym_api_requests::{
ecash::{
models::{
@@ -25,23 +23,21 @@ pub use nym_api_requests::{
VerifyEcashCredentialBody,
},
models::{
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
LegacyDescribedGateway, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
},
nym_nodes::{CachedNodesResponse, SkimmedNode},
};
pub use nym_coconut_dkg_common::types::EpochId;
use nym_contracts_common::IdentityKey;
pub use nym_http_api_client::Client;
use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, NodeId};
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use time::format_description::BorrowedFormatItem;
use time::Date;
use tracing::instrument;
pub mod error;
pub mod routes;
@@ -53,13 +49,11 @@ pub fn rfc_3339_date() -> Vec<BorrowedFormatItem<'static>> {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -73,7 +67,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -87,7 +80,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -103,14 +95,12 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> {
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
NO_PARAMS,
@@ -118,8 +108,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> {
async fn get_mixnodes_described(&self) -> Result<Vec<DescribedMixNode>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::DESCRIBED],
NO_PARAMS,
@@ -127,7 +116,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
@@ -151,7 +139,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
@@ -175,91 +162,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_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> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
@@ -268,7 +170,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -283,7 +184,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
@@ -292,10 +192,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_report(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
self.get_json(
&[
@@ -310,7 +209,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateway_report(
&self,
identity: IdentityKeyRef<'_>,
@@ -328,10 +226,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_history(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
self.get_json(
&[
@@ -346,7 +243,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateway_history(
&self,
identity: IdentityKeyRef<'_>,
@@ -364,7 +260,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -381,7 +276,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
@@ -413,10 +307,9 @@ pub trait NymApiClientExt: ApiClient {
}
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_core_status_count(
&self,
mix_id: NodeId,
mix_id: MixId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
if let Some(since) = since {
@@ -446,10 +339,9 @@ pub trait NymApiClientExt: ApiClient {
}
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_status(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeStatusResponse, NymAPIError> {
self.get_json(
&[
@@ -464,10 +356,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_reward_estimation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.get_json(
&[
@@ -482,10 +373,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn compute_mixnode_reward_estimation(
&self,
mix_id: NodeId,
mix_id: MixId,
request_body: &ComputeRewardEstParam,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.post_json(
@@ -502,10 +392,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_stake_saturation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<StakeSaturationResponse, NymAPIError> {
self.get_json(
&[
@@ -520,10 +409,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_inclusion_probability(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<InclusionProbabilityResponse, NymAPIError> {
self.get_json(
&[
@@ -538,24 +426,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_current_node_performance(
&self,
node_id: NodeId,
) -> Result<NodePerformanceResponse, NymAPIError> {
self.get_json_from(format!("/v1/nym-nodes/performance/{node_id}"))
.await
}
async fn get_node_annotation(
&self,
node_id: NodeId,
) -> Result<AnnotationResponse, NymAPIError> {
self.get_json_from(format!("/v1/nym-nodes/annotation/{node_id}"))
.await
}
async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> {
async fn get_mixnode_avg_uptime(&self, mix_id: MixId) -> Result<UptimeResponse, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
@@ -569,8 +440,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> {
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<MixId>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::BLACKLISTED],
NO_PARAMS,
@@ -578,7 +448,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::BLACKLISTED],
@@ -587,7 +456,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
@@ -604,7 +472,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn verify_ecash_ticket(
&self,
request_body: &VerifyEcashTicketBody,
@@ -621,7 +488,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn batch_redeem_ecash_tickets(
&self,
request_body: &BatchRedeemTicketsBody,
@@ -638,7 +504,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> {
self.get_json(
&[
@@ -651,7 +516,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn partial_expiration_date_signatures(
&self,
expiration_date: Option<Date>,
@@ -675,7 +539,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn partial_coin_indices_signatures(
&self,
epoch_id: Option<EpochId>,
@@ -696,7 +559,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn global_expiration_date_signatures(
&self,
expiration_date: Option<Date>,
@@ -720,7 +582,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn global_coin_indices_signatures(
&self,
epoch_id: Option<EpochId>,
@@ -741,7 +602,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn master_verification_key(
&self,
epoch_id: Option<EpochId>,
@@ -761,7 +621,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn epoch_credentials(
&self,
dkg_epoch: EpochId,
@@ -778,7 +637,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credential(
&self,
credential_id: i64,
@@ -795,7 +653,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credentials(
&self,
credential_ids: Vec<i64>,
@@ -38,7 +38,6 @@ pub mod ecash {
pub const STATUS_ROUTES: &str = "status";
pub const MIXNODE: &str = "mixnode";
pub const GATEWAY: &str = "gateway";
pub const NYM_NODES: &str = "nym-nodes";
pub const CORE_STATUS_COUNT: &str = "core-status-count";
pub const SINCE_ARG: &str = "since";
@@ -53,6 +52,5 @@ pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
pub const SUBMIT_GATEWAY: &str = "submit-gateway-monitoring-results";
pub const SUBMIT_NODE: &str = "submit-node-monitoring-results";
pub const PERFORMANCE: &str = "performance";
pub const SERVICE_PROVIDERS: &str = "services";
@@ -8,9 +8,9 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use cosmwasm_std::Addr;
use log::trace;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
use serde::Deserialize;
use tracing::trace;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
pub use nym_coconut_dkg_common::{
@@ -8,33 +8,28 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::Nonce;
use nym_mixnet_contract_common::gateway::{PreassignedGatewayIdsResponse, PreassignedId};
use nym_mixnet_contract_common::nym_node::{
EpochAssignmentResponse, NodeDetailsByIdentityResponse, NodeOwnershipResponse,
NodeRewardingDetailsResponse, PagedNymNodeBondsResponse, PagedNymNodeDetailsResponse,
PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse, StakeSaturationResponse,
UnbondedNodeResponse, UnbondedNymNode,
};
use nym_mixnet_contract_common::reward_params::WorkFactor;
use nym_mixnet_contract_common::{
delegation,
delegation::{NodeDelegationResponse, OwnerProxySubKey},
delegation::{MixNodeDelegationResponse, OwnerProxySubKey},
families::{Family, FamilyHead},
mixnode::{
MixStakeSaturationResponse, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, UnbondedMixnodeResponse,
MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
},
reward_params::{Performance, RewardingParams},
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond,
MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
PendingIntervalEventResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
RewardedSet, UnbondedMixnode,
Delegation, EpochEventId, EpochStatus, FamilyByHeadResponse, FamilyByLabelResponse,
FamilyMembersByHeadResponse, FamilyMembersByLabelResponse, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, LayerDistribution,
MixId, MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse,
MixnodeDetailsResponse, NumberOfPendingEventsResponse, PagedAllDelegationsResponse,
PagedDelegatorDelegationsResponse, PagedFamiliesResponse, PagedGatewayResponse,
PagedMembersResponse, PagedMixNodeDelegationsResponse, PagedMixnodeBondsResponse,
PagedRewardedSetResponse, PendingEpochEvent, PendingEpochEventResponse,
PendingEpochEventsResponse, PendingIntervalEvent, PendingIntervalEventResponse,
PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg, RewardedSetNodeStatus,
UnbondedMixnode,
};
use serde::Deserialize;
@@ -96,11 +91,56 @@ pub trait MixnetQueryClient {
.await
}
async fn get_rewarded_set_paged(
&self,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedRewardedSetResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSet { limit, start_after })
.await
}
async fn get_all_node_families_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedFamiliesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after })
.await
}
async fn get_all_family_members_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedMembersResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllMembersPaged { limit, start_after })
.await
}
async fn get_family_members_by_head<S: Into<String> + Send>(
&self,
head: S,
) -> Result<FamilyMembersByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByHead { head: head.into() })
.await
}
async fn get_family_members_by_label<S: Into<String> + Send>(
&self,
label: S,
) -> Result<FamilyMembersByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByLabel {
label: label.into(),
})
.await
}
// mixnode-related:
async fn get_mixnode_bonds_paged(
&self,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedMixnodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after })
@@ -109,26 +149,26 @@ pub trait MixnetQueryClient {
async fn get_mixnodes_detailed_paged(
&self,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedMixnodesDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after })
.await
}
async fn get_unbonded_mixnodes_paged(
async fn get_unbonded_paged(
&self,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after })
.await
}
async fn get_unbonded_mixnodes_by_owner_paged(
async fn get_unbonded_by_owner_paged(
&self,
owner: &AccountId,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner {
@@ -139,10 +179,10 @@ pub trait MixnetQueryClient {
.await
}
async fn get_unbonded_mixnodes_by_identity_paged(
async fn get_unbonded_by_identity_paged(
&self,
identity_key: IdentityKeyRef<'_>,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
@@ -165,7 +205,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_details(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id })
.await
@@ -183,7 +223,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_rewarding_details(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id })
.await
@@ -191,24 +231,24 @@ pub trait MixnetQueryClient {
async fn get_mixnode_stake_saturation(
&self,
mix_id: NodeId,
) -> Result<MixStakeSaturationResponse, NyxdError> {
mix_id: MixId,
) -> Result<StakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id })
.await
}
async fn get_unbonded_mixnode_information(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<UnbondedMixnodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id })
.await
}
// async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
// self.query_mixnet_contract(MixnetQueryMsg::GetRoleDistribution {})
// .await
// }
async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetLayerDistribution {})
.await
}
// gateway-related:
@@ -241,142 +281,17 @@ pub trait MixnetQueryClient {
.await
}
async fn get_preassigned_gateway_ids_paged(
&self,
start_after: Option<IdentityKey>,
limit: Option<u32>,
) -> Result<PreassignedGatewayIdsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit })
.await
}
// nym-nodes related:
async fn get_nymnode_bonds_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedNymNodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after })
.await
}
async fn get_nymnodes_detailed_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedNymNodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after })
.await
}
async fn get_unbonded_nymnodes_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after })
.await
}
async fn get_unbonded_nymnodes_by_owner_paged(
&self,
owner: &AccountId,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
owner: owner.to_string(),
limit,
start_after,
})
.await
}
async fn get_unbonded_nymnodes_by_identity_paged(
&self,
identity_key: IdentityKeyRef<'_>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
identity_key: identity_key.to_string(),
limit,
start_after,
})
.await
}
async fn get_owned_nymnode(
&self,
address: &AccountId,
) -> Result<NodeOwnershipResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetOwnedNymNode {
address: address.to_string(),
})
.await
}
async fn get_nymnode_details(
&self,
node_id: NodeId,
) -> Result<NodeOwnershipResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetails { node_id })
.await
}
async fn get_nymnode_details_by_identity(
&self,
node_identity: IdentityKey,
) -> Result<NodeDetailsByIdentityResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity })
.await
}
async fn get_nymnode_rewarding_details(
&self,
node_id: NodeId,
) -> Result<NodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeRewardingDetails { node_id })
.await
}
async fn get_node_stake_saturation(
&self,
node_id: NodeId,
) -> Result<StakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeStakeSaturation { node_id })
.await
}
async fn get_unbonded_nymnode_information(
&self,
node_id: NodeId,
) -> Result<UnbondedNodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNode { node_id })
.await
}
async fn get_role_assignment(&self, role: Role) -> Result<EpochAssignmentResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRoleAssignment { role })
.await
}
async fn get_rewarded_set_metadata(&self) -> Result<RolesMetadataResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSetMetadata {})
.await
}
// delegation-related:
/// Gets list of all delegations towards particular mixnode on particular page.
async fn get_mixnode_delegations_paged(
&self,
node_id: NodeId,
mix_id: MixId,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeDelegations {
node_id,
) -> Result<PagedMixNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDelegations {
mix_id,
start_after,
limit,
})
@@ -387,7 +302,7 @@ pub trait MixnetQueryClient {
async fn get_delegator_delegations_paged(
&self,
delegator: &AccountId,
start_after: Option<(NodeId, OwnerProxySubKey)>,
start_after: Option<(MixId, OwnerProxySubKey)>,
limit: Option<u32>,
) -> Result<PagedDelegatorDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations {
@@ -401,12 +316,12 @@ pub trait MixnetQueryClient {
/// Checks value of delegation of given client towards particular mixnode.
async fn get_delegation_details(
&self,
node_id: NodeId,
mix_id: MixId,
delegator: &AccountId,
proxy: Option<String>,
) -> Result<NodeDelegationResponse, NyxdError> {
) -> Result<MixNodeDelegationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegationDetails {
node_id,
mix_id,
delegator: delegator.to_string(),
proxy,
})
@@ -436,21 +351,21 @@ pub trait MixnetQueryClient {
async fn get_pending_mixnode_operator_reward(
&self,
node_id: NodeId,
mix_id: MixId,
) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingNodeOperatorReward { node_id })
self.query_mixnet_contract(MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id })
.await
}
async fn get_pending_delegator_reward(
&self,
delegator: &AccountId,
node_id: NodeId,
mix_id: MixId,
proxy: Option<String>,
) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingDelegatorReward {
address: delegator.to_string(),
node_id,
mix_id,
proxy,
})
.await
@@ -459,14 +374,12 @@ pub trait MixnetQueryClient {
// given the provided performance, estimate the reward at the end of the current epoch
async fn get_estimated_current_epoch_operator_reward(
&self,
node_id: NodeId,
mix_id: MixId,
estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
node_id,
mix_id,
estimated_performance,
estimated_work,
})
.await
}
@@ -475,15 +388,15 @@ pub trait MixnetQueryClient {
async fn get_estimated_current_epoch_delegator_reward(
&self,
delegator: &AccountId,
node_id: NodeId,
mix_id: MixId,
proxy: Option<String>,
estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address: delegator.to_string(),
node_id,
mix_id,
proxy,
estimated_performance,
estimated_work,
})
.await
}
@@ -537,6 +450,22 @@ pub trait MixnetQueryClient {
})
.await
}
async fn get_node_family_by_label(
&self,
label: String,
) -> Result<FamilyByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel { label })
.await
}
async fn get_node_family_by_head(
&self,
head: String,
) -> Result<FamilyByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead { head })
.await
}
}
// extension trait to the query client to deal with the paged queries
@@ -544,35 +473,18 @@ pub trait MixnetQueryClient {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedMixnetQueryClient: MixnetQueryClient {
async fn get_all_nymnode_bonds(&self) -> Result<Vec<NymNodeBond>, NyxdError> {
collect_paged!(self, get_nymnode_bonds_paged, nodes)
async fn get_all_node_families(&self) -> Result<Vec<Family>, NyxdError> {
collect_paged!(self, get_all_node_families_paged, families)
}
async fn get_all_nymnodes_detailed(&self) -> Result<Vec<NymNodeDetails>, NyxdError> {
collect_paged!(self, get_nymnodes_detailed_paged, nodes)
async fn get_all_family_members(&self) -> Result<Vec<(IdentityKey, FamilyHead)>, NyxdError> {
collect_paged!(self, get_all_family_members_paged, members)
}
async fn get_all_unbonded_nymnodes(&self) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(self, get_unbonded_nymnodes_paged, nodes)
}
async fn get_all_unbonded_nymnodes_by_owner(
async fn get_all_rewarded_set_mixnodes(
&self,
owner: &AccountId,
) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(self, get_unbonded_nymnodes_by_owner_paged, nodes, owner)
}
async fn get_all_unbonded_nymnodes_by_identity(
&self,
identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(
self,
get_unbonded_nymnodes_by_identity_paged,
nodes,
identity_key
)
) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, NyxdError> {
collect_paged!(self, get_rewarded_set_paged, nodes)
}
async fn get_all_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, NyxdError> {
@@ -583,40 +495,31 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
collect_paged!(self, get_mixnodes_detailed_paged, nodes)
}
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_paged, nodes)
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_paged, nodes)
}
async fn get_all_unbonded_mixnodes_by_owner(
&self,
owner: &AccountId,
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_by_owner_paged, nodes, owner)
) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_by_owner_paged, nodes, owner)
}
async fn get_all_unbonded_mixnodes_by_identity(
&self,
identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(
self,
get_unbonded_mixnodes_by_identity_paged,
nodes,
identity_key
)
) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_by_identity_paged, nodes, identity_key)
}
async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, NyxdError> {
collect_paged!(self, get_gateways_paged, nodes)
}
async fn get_all_preassigned_gateway_ids(&self) -> Result<Vec<PreassignedId>, NyxdError> {
collect_paged!(self, get_preassigned_gateway_ids_paged, ids)
}
async fn get_all_single_mixnode_delegations(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<Vec<Delegation>, NyxdError> {
collect_paged!(self, get_mixnode_delegations_paged, delegations, mix_id)
}
@@ -651,65 +554,6 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
#[async_trait]
impl<T> PagedMixnetQueryClient for T where T: MixnetQueryClient {}
// extension help to provide extra functionalities based on existing queries:
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait MixnetQueryClientExt: MixnetQueryClient {
async fn get_rewarded_set(&self) -> Result<RewardedSet, NyxdError> {
let error_response = |message| Err(NyxdError::extension_query_failure("mixnet", message));
let metadata = self.get_rewarded_set_metadata().await?;
if !metadata.metadata.fully_assigned {
return error_response("the rewarded set hasn't been fully assigned for this epoch");
}
let expected_epoch_id = metadata.metadata.epoch_id;
// if we have to query those things more frequently, we could do it concurrently,
// but as it stands now, it happens so infrequently it might as well be sequential
let entry = self.get_role_assignment(Role::EntryGateway).await?;
if entry.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'entry' returned unexpected epoch_id");
}
let exit = self.get_role_assignment(Role::ExitGateway).await?;
if exit.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'exit' returned unexpected epoch_id");
}
let layer1 = self.get_role_assignment(Role::Layer1).await?;
if layer1.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer1' returned unexpected epoch_id");
}
let layer2 = self.get_role_assignment(Role::Layer2).await?;
if layer2.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer2' returned unexpected epoch_id");
}
let layer3 = self.get_role_assignment(Role::Layer3).await?;
if layer3.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer3' returned unexpected epoch_id");
}
let standby = self.get_role_assignment(Role::Standby).await?;
if standby.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'standby' returned unexpected epoch_id");
}
Ok(RewardedSet {
entry_gateways: entry.nodes,
exit_gateways: exit.nodes,
layer1: layer1.nodes,
layer2: layer2.nodes,
layer3: layer3.nodes,
standby: standby.nodes,
})
}
}
#[async_trait]
impl<T> MixnetQueryClientExt for T where T: MixnetQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> MixnetQueryClient for C
@@ -741,6 +585,24 @@ mod tests {
) -> u32 {
match msg {
MixnetQueryMsg::Admin {} => client.admin().ignore(),
MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after } => client
.get_all_family_members_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetAllMembersPaged { limit, start_after } => client
.get_all_family_members_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetFamilyByHead { head } => {
client.get_node_family_by_head(head).ignore()
}
MixnetQueryMsg::GetFamilyByLabel { label } => {
client.get_node_family_by_label(label).ignore()
}
MixnetQueryMsg::GetFamilyMembersByHead { head } => {
client.get_family_members_by_head(head).ignore()
}
MixnetQueryMsg::GetFamilyMembersByLabel { label } => {
client.get_family_members_by_label(label).ignore()
}
MixnetQueryMsg::GetContractVersion {} => client.get_mixnet_contract_version().ignore(),
MixnetQueryMsg::GetCW2ContractVersion {} => {
client.get_mixnet_contract_cw2_version().ignore()
@@ -755,28 +617,31 @@ mod tests {
MixnetQueryMsg::GetCurrentIntervalDetails {} => {
client.get_current_interval_details().ignore()
}
MixnetQueryMsg::GetRewardedSet { limit, start_after } => {
client.get_rewarded_set_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetMixNodeBonds { limit, start_after } => {
client.get_mixnode_bonds_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetMixNodesDetailed { limit, start_after } => client
.get_mixnodes_detailed_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => client
.get_unbonded_mixnodes_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => {
client.get_unbonded_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetUnbondedMixNodesByOwner {
owner,
limit,
start_after,
} => client
.get_unbonded_mixnodes_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
.get_unbonded_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
identity_key,
limit,
start_after,
} => client
.get_unbonded_mixnodes_by_identity_paged(&identity_key, start_after, limit)
.get_unbonded_by_identity_paged(&identity_key, start_after, limit)
.ignore(),
MixnetQueryMsg::GetOwnedMixnode { address } => {
client.get_owned_mixnode(&address.parse().unwrap()).ignore()
@@ -796,6 +661,7 @@ mod tests {
MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { mix_identity } => client
.get_mixnode_details_by_identity(mix_identity)
.ignore(),
MixnetQueryMsg::GetLayerDistribution {} => client.get_layer_distribution().ignore(),
MixnetQueryMsg::GetGateways { start_after, limit } => {
client.get_gateways_paged(start_after, limit).ignore()
}
@@ -805,8 +671,8 @@ mod tests {
MixnetQueryMsg::GetOwnedGateway { address } => {
client.get_owned_gateway(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetNodeDelegations {
node_id: mix_id,
MixnetQueryMsg::GetMixnodeDelegations {
mix_id,
start_after,
limit,
} => client
@@ -820,7 +686,7 @@ mod tests {
.get_delegator_delegations_paged(&delegator.parse().unwrap(), start_after, limit)
.ignore(),
MixnetQueryMsg::GetDelegationDetails {
node_id: mix_id,
mix_id,
delegator,
proxy,
} => client
@@ -832,38 +698,33 @@ mod tests {
MixnetQueryMsg::GetPendingOperatorReward { address } => client
.get_pending_operator_reward(&address.parse().unwrap())
.ignore(),
MixnetQueryMsg::GetPendingNodeOperatorReward { node_id: mix_id } => {
MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id } => {
client.get_pending_mixnode_operator_reward(mix_id).ignore()
}
MixnetQueryMsg::GetPendingDelegatorReward {
address,
node_id: mix_id,
mix_id,
proxy,
} => client
.get_pending_delegator_reward(&address.parse().unwrap(), mix_id, proxy)
.ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
node_id,
mix_id,
estimated_performance,
estimated_work,
} => client
.get_estimated_current_epoch_operator_reward(
node_id,
estimated_performance,
estimated_work,
)
.get_estimated_current_epoch_operator_reward(mix_id, estimated_performance)
.ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address,
node_id,
mix_id,
proxy,
estimated_performance,
estimated_work,
} => client
.get_estimated_current_epoch_delegator_reward(
&address.parse().unwrap(),
node_id,
mix_id,
proxy,
estimated_performance,
estimated_work,
)
.ignore(),
MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => client
@@ -884,54 +745,6 @@ mod tests {
MixnetQueryMsg::GetSigningNonce { address } => {
client.get_signing_nonce(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit } => client
.get_preassigned_gateway_ids_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after } => {
client.get_nymnode_bonds_paged(limit, start_after).ignore()
}
MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after } => client
.get_nymnodes_detailed_paged(limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNode { node_id } => {
client.get_unbonded_nymnode_information(node_id).ignore()
}
MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after } => client
.get_unbonded_nymnodes_paged(limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
owner,
limit,
start_after,
} => client
.get_unbonded_nymnodes_by_owner_paged(&owner.parse().unwrap(), limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
identity_key,
limit,
start_after,
} => client
.get_unbonded_nymnodes_by_identity_paged(&identity_key, limit, start_after)
.ignore(),
MixnetQueryMsg::GetOwnedNymNode { address } => {
client.get_owned_nymnode(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetNymNodeDetails { node_id } => {
client.get_nymnode_details(node_id).ignore()
}
MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity } => client
.get_nymnode_details_by_identity(node_identity)
.ignore(),
MixnetQueryMsg::GetNodeRewardingDetails { node_id } => {
client.get_nymnode_rewarding_details(node_id).ignore()
}
MixnetQueryMsg::GetNodeStakeSaturation { node_id } => {
client.get_node_stake_saturation(node_id).ignore()
}
MixnetQueryMsg::GetRoleAssignment { role } => client.get_role_assignment(role).ignore(),
MixnetQueryMsg::GetRewardedSetMetadata {} => {
client.get_rewarded_set_metadata().ignore()
}
}
}
}
@@ -10,15 +10,13 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use nym_mixnet_contract_common::nym_node::NodeConfigUpdate;
use nym_mixnet_contract_common::reward_params::{
ActiveSetUpdate, IntervalRewardingParamsUpdate, NodeRewardingParameters,
};
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
use nym_mixnet_contract_common::{
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId, NymNode,
RoleAssignment,
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, Layer, LayerAssignment, MixId,
MixNode,
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -72,14 +70,14 @@ pub trait MixnetSigningClient {
async fn update_active_set_size(
&self,
update: ActiveSetUpdate,
active_set_size: u32,
force_immediately: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateActiveSetDistribution {
update,
MixnetExecuteMsg::UpdateActiveSetSize {
active_set_size,
force_immediately,
},
vec![],
@@ -128,6 +126,37 @@ pub trait MixnetSigningClient {
.await
}
async fn advance_current_epoch(
&self,
new_rewarded_set: Vec<LayerAssignment>,
expected_active_set_size: u32,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::AdvanceCurrentEpoch {
new_rewarded_set,
expected_active_set_size,
},
vec![],
)
.await
}
async fn assign_node_layer(
&self,
mix_id: MixId,
layer: Layer,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::AssignNodeLayer { mix_id, layer },
vec![],
)
.await
}
async fn reconcile_epoch_events(
&self,
limit: Option<u32>,
@@ -141,21 +170,126 @@ pub trait MixnetSigningClient {
.await
}
async fn assign_roles(
// family related
async fn create_family(
&self,
assignment: RoleAssignment,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::AssignRoles { assignment }, vec![])
self.execute_mixnet_contract(fee, MixnetExecuteMsg::CreateFamily { label }, vec![])
.await
}
async fn create_family_on_behalf(
&self,
owner_address: String,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::CreateFamilyOnBehalf {
owner_address,
label,
},
vec![],
)
.await
}
async fn join_family(
&self,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::JoinFamily {
join_permit,
family_head,
},
vec![],
)
.await
}
async fn join_family_on_behalf(
&self,
member_address: String,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::JoinFamilyOnBehalf {
member_address,
join_permit,
family_head,
},
vec![],
)
.await
}
async fn leave_family(
&self,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::LeaveFamily { family_head }, vec![])
.await
}
async fn leave_family_on_behalf(
&self,
member_address: String,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::LeaveFamilyOnBehalf {
member_address,
family_head,
},
vec![],
)
.await
}
async fn kick_family_member(
&self,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::KickFamilyMember { member }, vec![])
.await
}
async fn kick_family_member_on_behalf(
&self,
head_address: String,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
head_address,
member,
},
vec![],
)
.await
}
// mixnode-related:
async fn bond_mixnode(
&self,
mix_node: MixNode,
cost_params: NodeCostParams,
cost_params: MixNodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -176,7 +310,7 @@ pub trait MixnetSigningClient {
&self,
owner: AccountId,
mix_node: MixNode,
cost_params: NodeCostParams,
cost_params: MixNodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -275,14 +409,14 @@ pub trait MixnetSigningClient {
.await
}
async fn update_cost_params(
async fn update_mixnode_cost_params(
&self,
new_costs: NodeCostParams,
new_costs: MixNodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateCostParams { new_costs },
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs },
vec![],
)
.await
@@ -291,7 +425,7 @@ pub trait MixnetSigningClient {
async fn update_mixnode_cost_params_on_behalf(
&self,
owner: AccountId,
new_costs: NodeCostParams,
new_costs: MixNodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -425,75 +559,26 @@ pub trait MixnetSigningClient {
.await
}
// nym-node related:
async fn migrate_legacy_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateMixnode {}, vec![])
.await
}
async fn migrate_legacy_gateway(
&self,
cost_params: Option<NodeCostParams>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::MigrateGateway { cost_params },
vec![],
)
.await
}
async fn bond_nymnode(
&self,
node: NymNode,
cost_params: NodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::BondNymNode {
node,
cost_params,
owner_signature,
},
vec![pledge],
)
.await
}
async fn unbond_nymnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondNymNode {}, vec![])
.await
}
async fn update_nymnode_config(
&self,
update: NodeConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UpdateNodeConfig { update }, vec![])
.await
}
// delegation-related:
async fn delegate(
async fn delegate_to_mixnode(
&self,
node_id: NodeId,
mix_id: MixId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Delegate { node_id }, vec![amount])
.await
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::DelegateToMixnode { mix_id },
vec![amount],
)
.await
}
async fn delegate_to_mixnode_on_behalf(
&self,
delegate: AccountId,
mix_id: NodeId,
mix_id: MixId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -508,19 +593,23 @@ pub trait MixnetSigningClient {
.await
}
async fn undelegate(
async fn undelegate_from_mixnode(
&self,
node_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Undelegate { node_id }, vec![])
.await
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UndelegateFromMixnode { mix_id },
vec![],
)
.await
}
async fn undelegate_to_mixnode_on_behalf(
&self,
delegate: AccountId,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -536,15 +625,18 @@ pub trait MixnetSigningClient {
// reward-related
async fn reward_node(
async fn reward_mixnode(
&self,
node_id: NodeId,
params: NodeRewardingParameters,
mix_id: MixId,
performance: Performance,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::RewardNode { node_id, params },
MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
},
vec![],
)
.await
@@ -572,12 +664,12 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward(
&self,
node_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::WithdrawDelegatorReward { node_id },
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id },
vec![],
)
.await
@@ -586,7 +678,7 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward_on_behalf(
&self,
owner: AccountId,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -607,7 +699,7 @@ pub trait MixnetSigningClient {
async fn migrate_vested_delegation(
&self,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -669,7 +761,6 @@ where
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
use nym_mixnet_contract_common::ExecuteMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
@@ -679,17 +770,56 @@ mod tests {
) {
match msg {
MixnetExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(),
MixnetExecuteMsg::AssignNodeLayer { mix_id, layer } => {
client.assign_node_layer(mix_id, layer, None).ignore()
}
MixnetExecuteMsg::CreateFamily { label } => client.create_family(label, None).ignore(),
MixnetExecuteMsg::JoinFamily {
join_permit,
family_head,
} => client.join_family(join_permit, family_head, None).ignore(),
MixnetExecuteMsg::LeaveFamily { family_head } => {
client.leave_family(family_head, None).ignore()
}
MixnetExecuteMsg::KickFamilyMember { member } => {
client.kick_family_member(member, None).ignore()
}
MixnetExecuteMsg::CreateFamilyOnBehalf {
owner_address,
label,
} => client
.create_family_on_behalf(owner_address, label, None)
.ignore(),
MixnetExecuteMsg::JoinFamilyOnBehalf {
member_address,
join_permit,
family_head,
} => client
.join_family_on_behalf(member_address, join_permit, family_head, None)
.ignore(),
MixnetExecuteMsg::LeaveFamilyOnBehalf {
member_address,
family_head,
} => client
.leave_family_on_behalf(member_address, family_head, None)
.ignore(),
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
head_address,
member,
} => client
.kick_family_member_on_behalf(head_address, member, None)
.ignore(),
MixnetExecuteMsg::UpdateRewardingValidatorAddress { address } => client
.update_rewarding_validator_address(address.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::UpdateContractStateParams { updated_parameters } => client
.update_contract_state_params(updated_parameters, None)
.ignore(),
MixnetExecuteMsg::UpdateActiveSetDistribution {
update,
MixnetExecuteMsg::UpdateActiveSetSize {
active_set_size,
force_immediately,
} => client
.update_active_set_size(update, force_immediately, None)
.update_active_set_size(active_set_size, force_immediately, None)
.ignore(),
MixnetExecuteMsg::UpdateRewardingParams {
updated_params,
@@ -712,6 +842,12 @@ mod tests {
MixnetExecuteMsg::BeginEpochTransition {} => {
client.begin_epoch_transition(None).ignore()
}
MixnetExecuteMsg::AdvanceCurrentEpoch {
new_rewarded_set,
expected_active_set_size,
} => client
.advance_current_epoch(new_rewarded_set, expected_active_set_size, None)
.ignore(),
MixnetExecuteMsg::ReconcileEpochEvents { limit } => {
client.reconcile_epoch_events(limit, None).ignore()
}
@@ -751,8 +887,8 @@ mod tests {
MixnetExecuteMsg::UnbondMixnodeOnBehalf { owner } => client
.unbond_mixnode_on_behalf(owner.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::UpdateCostParams { new_costs } => {
client.update_cost_params(new_costs, None).ignore()
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs } => {
client.update_mixnode_cost_params(new_costs, None).ignore()
}
MixnetExecuteMsg::UpdateMixnodeCostParamsOnBehalf { new_costs, owner } => client
.update_mixnode_cost_params_on_behalf(owner.parse().unwrap(), new_costs, None)
@@ -792,28 +928,29 @@ mod tests {
MixnetExecuteMsg::UpdateGatewayConfigOnBehalf { new_config, owner } => client
.update_gateway_config_on_behalf(owner.parse().unwrap(), new_config, None)
.ignore(),
MixnetExecuteMsg::Delegate { node_id: mix_id } => {
client.delegate(mix_id, mock_coin(), None).ignore()
}
MixnetExecuteMsg::DelegateToMixnode { mix_id } => client
.delegate_to_mixnode(mix_id, mock_coin(), None)
.ignore(),
MixnetExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, delegate } => client
.delegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, mock_coin(), None)
.ignore(),
MixnetExecuteMsg::Undelegate { node_id: mix_id } => {
client.undelegate(mix_id, None).ignore()
MixnetExecuteMsg::UndelegateFromMixnode { mix_id } => {
client.undelegate_from_mixnode(mix_id, None).ignore()
}
MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_id, delegate } => client
.undelegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, None)
.ignore(),
MixnetExecuteMsg::RewardNode { node_id, params } => {
client.reward_node(node_id, params, None).ignore()
}
MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
} => client.reward_mixnode(mix_id, performance, None).ignore(),
MixnetExecuteMsg::WithdrawOperatorReward {} => {
client.withdraw_operator_reward(None).ignore()
}
MixnetExecuteMsg::WithdrawOperatorRewardOnBehalf { owner } => client
.withdraw_operator_reward_on_behalf(owner.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::WithdrawDelegatorReward { node_id: mix_id } => {
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id } => {
client.withdraw_delegator_reward(mix_id, None).ignore()
}
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
@@ -826,25 +963,6 @@ mod tests {
client.migrate_vested_delegation(mix_id, None).ignore()
}
ExecuteMsg::AssignRoles { assignment } => {
client.assign_roles(assignment, None).ignore()
}
ExecuteMsg::MigrateMixnode {} => client.migrate_legacy_mixnode(None).ignore(),
ExecuteMsg::MigrateGateway { cost_params } => {
client.migrate_legacy_gateway(cost_params, None).ignore()
}
ExecuteMsg::BondNymNode {
node,
cost_params,
owner_signature,
} => client
.bond_nymnode(node, cost_params, owner_signature, mock_coin(), None)
.ignore(),
ExecuteMsg::UnbondNymNode {} => client.unbond_nymnode(None).ignore(),
ExecuteMsg::UpdateNodeConfig { update } => {
client.update_nymnode_config(update, None).ignore()
}
#[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
client.testing_resolve_all_pending_events(None).ignore()
@@ -9,7 +9,7 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use nym_contracts_common::ContractBuildInformation;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse,
AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse,
@@ -238,7 +238,7 @@ pub trait VestingQueryClient {
async fn get_vesting_delegation(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
block_timestamp_secs: u64,
) -> Result<VestingDelegation, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegation {
@@ -252,7 +252,7 @@ pub trait VestingQueryClient {
async fn get_total_delegation_amount(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
) -> Result<Coin, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetTotalDelegationAmount {
address: address.to_string(),
@@ -264,7 +264,7 @@ pub trait VestingQueryClient {
async fn get_delegation_timestamps(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
) -> Result<DelegationTimesResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegationTimes {
address: address.to_string(),
@@ -275,7 +275,7 @@ pub trait VestingQueryClient {
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, NodeId, u64)>,
start_after: Option<(u32, MixId, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetAllDelegations { start_after, limit })
@@ -9,9 +9,10 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixNode, NodeId};
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
use nym_vesting_contract_common::messages::ExecuteMsg as VestingExecuteMsg;
use nym_vesting_contract_common::{PledgeCap, VestingSpecification};
@@ -27,7 +28,7 @@ pub trait VestingSigningClient {
async fn vesting_update_mixnode_cost_params(
&self,
new_costs: NodeCostParams,
new_costs: MixNodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
@@ -123,7 +124,7 @@ pub trait VestingSigningClient {
async fn vesting_bond_mixnode(
&self,
mix_node: MixNode,
cost_params: NodeCostParams,
cost_params: MixNodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -203,7 +204,7 @@ pub trait VestingSigningClient {
async fn vesting_track_undelegation(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -221,7 +222,7 @@ pub trait VestingSigningClient {
async fn vesting_delegate_to_mixnode(
&self,
mix_id: NodeId,
mix_id: MixId,
amount: Coin,
on_behalf_of: Option<String>,
fee: Option<Fee>,
@@ -240,7 +241,7 @@ pub trait VestingSigningClient {
async fn vesting_undelegate_from_mixnode(
&self,
mix_id: NodeId,
mix_id: MixId,
on_behalf_of: Option<String>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -300,7 +301,7 @@ pub trait VestingSigningClient {
async fn vesting_withdraw_delegator_reward(
&self,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
@@ -353,6 +354,50 @@ pub trait VestingSigningClient {
)
.await
}
async fn vesting_create_family(
&self,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::CreateFamily { label }, vec![])
.await
}
async fn vesting_join_family(
&self,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
fee,
VestingExecuteMsg::JoinFamily {
join_permit,
family_head,
},
vec![],
)
.await
}
async fn vesting_leave_family(
&self,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::LeaveFamily { family_head }, vec![])
.await
}
async fn vesting_kick_family_member(
&self,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::KickFamilyMember { member }, vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -401,6 +446,21 @@ mod tests {
msg: VestingExecuteMsg,
) {
match msg {
VestingExecuteMsg::CreateFamily { label } => {
client.vesting_create_family(label, None).ignore()
}
VestingExecuteMsg::JoinFamily {
join_permit,
family_head,
} => client
.vesting_join_family(join_permit, family_head, None)
.ignore(),
VestingExecuteMsg::LeaveFamily { family_head } => {
client.vesting_leave_family(family_head, None).ignore()
}
VestingExecuteMsg::KickFamilyMember { member } => {
client.vesting_kick_family_member(member, None).ignore()
}
VestingExecuteMsg::TrackReward { amount, address } => client
.vesting_track_reward(amount.into(), address, None)
.ignore(),
@@ -5,7 +5,7 @@ use crate::nyxd;
use crate::nyxd::coin::Coin;
use crate::nyxd::cosmwasm_client::helpers::{create_pagination, next_page_key};
use crate::nyxd::cosmwasm_client::types::{
Account, CodeDetails, Contract, ContractCodeId, Model, SequenceResponse, SimulateResponse,
Account, CodeDetails, Contract, ContractCodeId, SequenceResponse, SimulateResponse,
};
use crate::nyxd::error::NyxdError;
use crate::nyxd::Query;
@@ -21,14 +21,15 @@ use cosmrs::proto::cosmos::tx::v1beta1::{
SimulateRequest, SimulateResponse as ProtoSimulateResponse,
};
use cosmrs::proto::cosmwasm::wasm::v1::{
QueryAllContractStateRequest, QueryAllContractStateResponse, QueryCodeRequest,
QueryCodeResponse, QueryCodesRequest, QueryCodesResponse, QueryContractHistoryRequest,
QueryContractHistoryResponse, QueryContractInfoRequest, QueryContractInfoResponse,
QueryContractsByCodeRequest, QueryContractsByCodeResponse, QueryRawContractStateRequest,
QueryRawContractStateResponse, QuerySmartContractStateRequest, QuerySmartContractStateResponse,
QueryCodeRequest, QueryCodeResponse, QueryCodesRequest, QueryCodesResponse,
QueryContractHistoryRequest, QueryContractHistoryResponse, QueryContractInfoRequest,
QueryContractInfoResponse, QueryContractsByCodeRequest, QueryContractsByCodeResponse,
QueryRawContractStateRequest, QueryRawContractStateResponse, QuerySmartContractStateRequest,
QuerySmartContractStateResponse,
};
use cosmrs::tendermint::{block, chain, Hash};
use cosmrs::{AccountId, Coin as CosmosCoin, Tx};
use log::trace;
use prost::Message;
use serde::{Deserialize, Serialize};
@@ -67,7 +68,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
Res: Message + Default,
{
if let Some(ref abci_path) = path {
tracing::trace!("performing query on abci path {abci_path}")
trace!("performing query on abci path {abci_path}")
}
let mut buf = Vec::with_capacity(req.encoded_len());
req.encode(&mut buf)?;
@@ -217,19 +218,17 @@ pub trait CosmWasmClient: TendermintRpcClient {
loop {
let mut res = self
.tx_search(query.clone(), false, page, per_page, Order::Ascending)
.tx_search(query.clone(), false, page, 100, Order::Ascending)
.await?;
results.append(&mut res.txs);
// sanity check for if tendermint's maximum per_page was modified -
// we don't want to accidentally be stuck in an infinite loop
let early_break = res.total_count == 0 || res.txs.is_empty();
results.append(&mut res.txs);
if early_break {
if res.total_count == 0 || res.txs.is_empty() {
break;
}
if res.total_count > results.len() as u32 {
if res.total_count >= per_page {
page += 1
} else {
break;
@@ -296,7 +295,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
let start = Instant::now();
loop {
tracing::debug!(
log::debug!(
"Polling for result of including {} in a block...",
broadcasted.hash
);
@@ -443,38 +442,6 @@ pub trait CosmWasmClient: TendermintRpcClient {
.collect::<Result<_, _>>()?)
}
async fn query_all_contract_state(&self, address: &AccountId) -> Result<Vec<Model>, NyxdError> {
let path = Some("/cosmwasm.wasm.v1.Query/AllContractState".to_owned());
let mut models = Vec::new();
let mut pagination = None;
loop {
let req = QueryAllContractStateRequest {
address: address.to_string(),
pagination,
};
let mut res = self
.make_abci_query::<_, QueryAllContractStateResponse>(path.clone(), req)
.await?;
let empty_response = res.models.is_empty();
models.append(&mut res.models);
if empty_response {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
break;
}
}
Ok(models.into_iter().map(Into::into).collect())
}
async fn query_contract_raw(
&self,
address: &AccountId,
@@ -521,7 +488,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QuerySmartContractStateResponse>(path, req)
.await?;
tracing::trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
Ok(serde_json::from_slice(&res.data)?)
}
@@ -25,12 +25,12 @@ use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{self, Msg};
use cosmrs::{cosmwasm, AccountId, Any, Tx};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use std::time::SystemTime;
use tendermint_rpc::endpoint::broadcast;
use tracing::debug;
fn empty_fee() -> tx::Fee {
tx::Fee {
@@ -7,9 +7,9 @@ use base64::Engine;
use cosmrs::abci::TxMsgData;
use cosmrs::cosmwasm::MsgExecuteContractResponse;
use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse};
use log::error;
use prost::bytes::Bytes;
use tendermint_rpc::endpoint::broadcast;
use tracing::error;
pub use cosmrs::abci::MsgResponse;
@@ -27,34 +27,13 @@ use cosmrs::vesting::{
};
use cosmrs::{AccountId, Any, Coin as CosmosCoin};
use prost::Message;
use serde::{Deserialize, Serialize};
use serde::Serialize;
pub use cosmrs::abci::GasInfo;
pub use cosmrs::abci::MsgResponse;
pub type ContractCodeId = u64;
// yet another thing to put in cosmrs
#[derive(Serialize, Deserialize)]
pub struct Model {
#[serde(with = "nym_serde_helpers::hex")]
pub key: Vec<u8>,
#[serde(with = "nym_serde_helpers::base64")]
pub value: Vec<u8>,
}
// follow the cosmwasm serialisation format, i.e. hex for key and base64 for value
impl From<cosmrs::proto::cosmwasm::wasm::v1::Model> for Model {
fn from(model: cosmrs::proto::cosmwasm::wasm::v1::Model) -> Self {
Model {
key: model.key,
value: model.value,
}
}
}
#[derive(Serialize)]
pub struct EmptyMsg {}
@@ -154,23 +154,6 @@ pub enum NyxdError {
#[error("the response data has invalid size. got {got} bytes, but expected {expected} bytes instead")]
MalformedResponseData { got: usize, expected: usize },
#[error(
"one of the extension query for {contract} failed with the following message: {message}"
)]
ExtensionQueryFailure { contract: String, message: String },
}
impl NyxdError {
pub fn extension_query_failure(
contract: impl Into<String>,
message: impl Into<String>,
) -> Self {
NyxdError::ExtensionQueryFailure {
contract: contract.into(),
message: message.into(),
}
}
}
// The purpose of parsing the abci query result is that we want to generate the `pretty_log` if
+1 -6
View File
@@ -9,15 +9,10 @@ use comfy_table::Table;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials_interface::TicketType;
use std::path::PathBuf;
#[derive(Debug, Parser)]
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.
/// By default, the current unspent value is used.
#[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 Some(mut next_ticketbook) = persistent_storage
.get_next_unspent_usable_ticketbook(args.ticketbook_type.to_string(), 0)
.get_next_unspent_usable_ticketbook(0)
.await?
else {
bail!(
@@ -1,6 +1,8 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
@@ -29,7 +31,7 @@ impl FromStr for CredentialDataWrapper {
pub struct Args {
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) credentials_store: PathBuf,
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded credential data (as base58)
#[clap(long, group = "cred_data")]
@@ -68,7 +70,21 @@ impl Args {
}
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 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?;
let ticketbook = credentials_store
.get_next_unspent_usable_ticketbook(args.ticketbook_type.to_string(), 0)
.get_next_unspent_usable_ticketbook(0)
.await?
.ok_or(anyhow!("we just issued a ticketbook, it must be present!"))?
.ticketbook;
@@ -4,7 +4,6 @@
use clap::Parser;
use cosmwasm_std::Decimal;
use log::{debug, info};
use nym_mixnet_contract_common::reward_params::RewardedSetParams;
use nym_mixnet_contract_common::{
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
};
@@ -57,17 +56,11 @@ pub struct Args {
#[clap(long, default_value_t = 2)]
pub interval_pool_emission: u64,
#[clap(long, default_value_t = 50)]
pub(crate) entry_gateways: u32,
#[clap(long, default_value_t = 240)]
pub rewarded_set_size: u32,
#[clap(long, default_value_t = 70)]
pub(crate) exit_gateways: u32,
#[clap(long, default_value_t = 120)]
pub(crate) mixnodes: u32,
#[clap(long, default_value_t = 0)]
pub(crate) standby: u32,
#[clap(long, default_value_t = 240)]
pub active_set_size: u32,
#[clap(long, default_value_t = Percent::zero())]
pub minimum_profit_margin_percent: Percent,
@@ -102,13 +95,8 @@ pub async fn generate(args: Args) {
.expect("active_set_work_factor can't be converted to Decimal"),
interval_pool_emission: Percent::from_percentage_value(args.interval_pool_emission)
.expect("interval_pool_emission can't be converted to Percent"),
rewarded_set_params: RewardedSetParams {
entry_gateways: args.entry_gateways,
exit_gateways: args.exit_gateways,
mixnodes: args.mixnodes,
standby: args.standby,
},
rewarded_set_size: args.rewarded_set_size,
active_set_size: args.active_set_size,
};
debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
@@ -7,14 +7,13 @@ pub mod execute_contract;
pub mod generators;
pub mod init_contract;
pub mod migrate_contract;
pub mod raw_contract_state;
pub mod upload_contract;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Cosmwasm {
#[clap(subcommand)]
pub command: CosmwasmCommands,
pub command: Option<CosmwasmCommands>,
}
#[derive(Debug, Subcommand)]
@@ -29,6 +28,4 @@ pub enum CosmwasmCommands {
Migrate(crate::validator::cosmwasm::migrate_contract::Args),
/// Execute a WASM smart contract method
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 clap::Parser;
use log::info;
use nym_mixnet_contract_common::{Coin, NodeId};
use nym_mixnet_contract_common::{Coin, MixId};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -43,7 +43,7 @@ pub async fn delegate_to_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let res = client
.delegate(mix_id, coin.into(), None)
.delegate_to_mixnode(mix_id, coin.into(), None)
.await
.expect("failed to delegate to mixnode!");
@@ -1,18 +1,21 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use clap::Parser;
use comfy_table::Table;
use csv::WriterBuilder;
use log::info;
use nym_mixnet_contract_common::ExecuteMsg;
use nym_mixnet_contract_common::PendingEpochEventKind;
use nym_mixnet_contract_common::ExecuteMsg::{DelegateToMixnode, UndelegateFromMixnode};
use nym_mixnet_contract_common::PendingEpochEventKind::{Delegate, Undelegate};
use nym_validator_client::nyxd::contract_traits::{NymContractsProvider, PagedMixnetQueryClient};
use nym_validator_client::nyxd::Coin;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use crate::context::SigningClient;
use crate::utils::pretty_coin;
@@ -37,7 +40,7 @@ pub struct Args {
#[derive(Debug)]
pub struct InputFileRow {
pub node_id: String,
pub mix_id: String,
pub amount: Coin,
}
#[derive(Debug)]
@@ -73,7 +76,7 @@ impl InputFileReader {
}
rows.push(InputFileRow {
node_id: mix_id,
mix_id,
amount: Coin {
amount: micro_nym_amount,
denom: "unym".to_string(),
@@ -137,10 +140,8 @@ async fn fetch_delegation_data(
let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new();
for delegation in delegations {
existing_delegation_map.insert(
delegation.node_id.to_string(),
Coin::from(delegation.amount),
);
existing_delegation_map
.insert(delegation.mix_id.to_string(), Coin::from(delegation.amount));
}
// Look for pending delegate / undelegate events which might be of interest to us
@@ -154,27 +155,27 @@ async fn fetch_delegation_data(
for event in pending_events {
match event.event.kind {
// If a pending undelegate tx is found, remove it from delegation map
PendingEpochEventKind::Undelegate { owner, node_id, .. } => {
Undelegate { owner, mix_id, .. } => {
if owner == address.as_ref()
&& existing_delegation_map.contains_key(&node_id.to_string())
&& existing_delegation_map.contains_key(&mix_id.to_string())
{
existing_delegation_map.remove(&node_id.to_string());
existing_delegation_map.remove(&mix_id.to_string());
}
}
// If a pending delegation event is found, gather them to consolidate later
PendingEpochEventKind::Delegate {
Delegate {
owner,
node_id,
mix_id,
amount,
..
} => {
if owner == address.as_ref() {
let mut amount = Coin::from(amount);
if let Some(pending_record) = pending_delegation_map.get(&node_id.to_string()) {
if let Some(pending_record) = pending_delegation_map.get(&mix_id.to_string()) {
amount.amount += pending_record.amount;
}
pending_delegation_map.insert(node_id.to_string(), amount);
pending_delegation_map.insert(mix_id.to_string(), amount);
}
}
_ => {}
@@ -216,7 +217,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
for row in &records.rows {
let input_amount = row.amount.amount;
let existing_delegation_amount = existing_delegation_map
.get(&row.node_id)
.get(&row.mix_id)
.map_or(0, |coin| coin.amount);
match existing_delegation_amount.cmp(&input_amount) {
@@ -228,26 +229,25 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
amount: input_amount - existing_delegation_amount,
denom: row.amount.denom.clone(),
};
let node_id = row.node_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((ExecuteMsg::Delegate { node_id }, vec![difference.clone()]));
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![difference.clone()]));
delegation_table.add_row(&[
row.node_id.clone(),
row.mix_id.clone(),
pretty_coin(&row.amount),
pretty_coin(&difference),
]);
}
Ordering::Greater => {
let node_id = row.node_id.clone().parse::<u32>().unwrap();
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
let coins: Vec<Coin> = vec![];
undelegation_msgs.push((ExecuteMsg::Undelegate { node_id }, coins));
undelegation_table.add_row(&[row.node_id.clone()]);
undelegation_msgs.push((UndelegateFromMixnode { mix_id }, coins));
undelegation_table.add_row(&[row.mix_id.clone()]);
if row.amount.amount > 0 {
delegation_msgs
.push((ExecuteMsg::Delegate { node_id }, vec![row.amount.clone()]));
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![row.amount.clone()]));
delegation_table.add_row(&[
row.node_id.clone(),
row.mix_id.clone(),
pretty_coin(&row.amount),
pretty_coin(&row.amount),
]);
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -66,7 +66,7 @@ async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientW
for delegation in delegations {
table.add_row(vec![
to_iso_timestamp(delegation.height as u32, client).await,
delegation.node_id.to_string(),
delegation.mix_id.to_string(),
pretty_cosmwasm_coin(&delegation.amount),
delegation
.proxy
@@ -93,7 +93,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
match event.event.kind {
PendingEpochEventKind::Delegate {
owner,
node_id: mix_id,
mix_id,
amount,
proxy,
..
@@ -110,7 +110,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
}
PendingEpochEventKind::Undelegate {
owner,
node_id: mix_id,
mix_id,
proxy,
..
} => {
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -36,7 +36,7 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
};
let res = client
.undelegate(mix_id, None)
.undelegate_from_mixnode(mix_id, None)
.await
.expect("failed to remove stake from mixnode!");
@@ -4,7 +4,7 @@
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::{Coin, NodeId};
use nym_mixnet_contract_common::{Coin, MixId};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -13,7 +13,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -3,7 +3,7 @@
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -12,7 +12,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -5,7 +5,6 @@ use clap::{Args, Subcommand};
pub mod bond_gateway;
pub mod gateway_bonding_sign_payload;
pub mod nymnode_migration;
pub mod settings;
pub mod unbond_gateway;
pub mod vesting_bond_gateway;
@@ -32,6 +31,4 @@ pub enum MixnetOperatorsGatewayCommands {
VestingUnbond(vesting_unbond_gateway::Args),
/// Create base58-encoded payload required for producing valid bonding signature.
CreateGatewayBondingSignPayload(gateway_bonding_sign_payload::Args),
/// Migrate the gateway into a Nym Node
MigrateToNymnode(nymnode_migration::Args),
}
@@ -1,56 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
NodeCostParams, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
}
pub async fn migrate_to_nymnode(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
let cost_params =
if args.profit_margin_percent.is_some() || args.interval_operating_cost.is_some() {
Some(NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
})
} else {
None
};
let res = client
.migrate_legacy_gateway(cost_params, None)
.await
.expect("failed to migrate gateway!");
info!("migration result: {:?}", res)
}
@@ -1,21 +1,20 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{
Coin, NodeCostParams, Percent, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT,
DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_mixnet_contract_common::{Coin, MixNodeCostParams, Percent};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
@@ -43,7 +42,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
pub profit_margin_percent: Option<u8>,
#[clap(
long,
@@ -86,18 +85,14 @@ pub async fn bond_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
args.profit_margin_percent.unwrap_or(10) as u64,
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
},
};
@@ -0,0 +1,25 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Label that is going to be used for creating the family
#[arg(long)]
pub family_label: String,
}
pub async fn create_family(args: Args, client: SigningClient) {
info!("Create family");
let res = client
.create_family(args.family_label, None)
.await
.expect("failed to create family");
info!("Family creation result: {:?}", res);
}
@@ -0,0 +1,72 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClient;
use crate::utils::DataWrapper;
use clap::Parser;
use cosmrs::AccountId;
use log::info;
use nym_bin_common::output_format::OutputFormat;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::construct_family_join_permit;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Account address (i.e. owner of the family head) which will be used for issuing the permit
#[arg(long)]
pub address: AccountId,
// might as well validate the value when parsing the arguments
/// Identity of the member for whom we're issuing the permit
#[arg(long)]
pub member: identity::PublicKey,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryClient) {
info!("Create family join permit sign payload");
// get the address of our mixnode to recover the family head information
let Some(mixnode) = client
.get_owned_mixnode(&args.address)
.await
.unwrap()
.mixnode_details
else {
eprintln!("{} does not seem to even own a mixnode!", args.address);
return;
};
// make sure this mixnode is actually a family head
if client
.get_node_family_by_head(mixnode.bond_information.identity().to_string())
.await
.unwrap()
.family
.is_none()
{
eprintln!("{} does not even seem to own a family!", args.address);
return;
}
let nonce = match client.get_signing_nonce(&args.address).await {
Ok(nonce) => nonce,
Err(err) => {
eprint!(
"failed to query for the signing nonce of {}: {err}",
args.address
);
return;
}
};
let head = FamilyHead::new(mixnode.bond_information.identity());
let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string());
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -0,0 +1,34 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_contracts_common::signing::MessageSignature;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The head of the family that we intend to join
#[arg(long)]
pub family_head: identity::PublicKey,
/// Permission, as provided by the family head, for joining the family
#[arg(long)]
pub join_permit: MessageSignature,
}
pub async fn join_family(args: Args, client: SigningClient) {
info!("Join family");
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.join_family(args.join_permit, family_head, None)
.await
.expect("failed to join family");
info!("Family join result: {:?}", res);
}

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