Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 34b8a0706d | |||
| 275417c186 | |||
| 40a92e07d6 | |||
| e83a12bd91 | |||
| 381162554e | |||
| 7a740c06fd | |||
| e65285ac7b | |||
| 715a3bd687 | |||
| 858f1ac13c | |||
| 3ee1328626 | |||
| 36ac825b43 | |||
| 165f189115 | |||
| b5fcfbe2fe | |||
| 7a38f1f469 | |||
| 5faca46235 | |||
| d780ac55b1 | |||
| c5f7d066b0 | |||
| 8cc90be8c6 | |||
| aae96e7537 | |||
| 39b521bc1f | |||
| 7339695ce8 | |||
| 0e1c9853aa | |||
| 76b9c669d7 | |||
| 553cfd098b | |||
| 40e1243f3c | |||
| 50d2ca0a12 | |||
| 32d9baaf02 | |||
| 0179f7648c | |||
| 45c04d63e2 | |||
| 0f8ac1506b | |||
| efdf27d1e9 |
@@ -109,7 +109,6 @@ jobs:
|
||||
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_service_provider_directory.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_name_service.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_ephemera.wasm $OUTPUT_DIR
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
name: CD dev-portal
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
paths:
|
||||
- 'documentation/dev-portal/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
|
||||
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck
|
||||
- name: Clean website
|
||||
run: cd documentation/dev-portal && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/dev-portal && mdbook build
|
||||
- name: Deploy branch master to dev
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/dev-portal/book/html/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch master to prod
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/dev-portal/book/html/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
|
||||
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: cd-dev
|
||||
NYM_PROJECT_NAME: "Dev portal 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_DEVP }}"
|
||||
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
|
||||
@@ -1,7 +1,6 @@
|
||||
name: CD docs
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: master
|
||||
paths:
|
||||
@@ -28,38 +27,39 @@ jobs:
|
||||
command: build
|
||||
args: --workspace --release --all
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "=0.2.2" mdbook-variables && cargo install \
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
|
||||
&& cargo install --vers "^0.7.7" mdbook-linkcheck
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
run: cd documentation && ./build_all_to_dist.sh
|
||||
continue-on-error: false
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
|
||||
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
|
||||
cargo install --vers "^0.5.0" mdbook-cmdrun
|
||||
- name: Clean website
|
||||
run: cd documentation/docs && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/docs && mdbook build
|
||||
- name: Deploy branch master to dev
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "dist/docs/"
|
||||
SOURCE: "documentation/docs/book/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
|
||||
EXCLUDE: "/node_modules/"
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Deploy branch master to prod
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "dist/docs/"
|
||||
SOURCE: "documentation/docs/book/"
|
||||
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
|
||||
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
|
||||
EXCLUDE: "/node_modules/"
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
name: Check Contract Schema
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- 'common/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- 'common/**'
|
||||
|
||||
jobs:
|
||||
check-schema:
|
||||
name: Generate and check schema
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
|
||||
- name: Generate the schema
|
||||
run: make contract-schema
|
||||
|
||||
- name: Check for diff
|
||||
run: git diff --exit-code -- contracts/*/schema
|
||||
@@ -0,0 +1,66 @@
|
||||
name: CI dev-portal
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: master
|
||||
paths:
|
||||
- 'documentation/dev-portal/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
|
||||
&& cargo install --vers "^0.7.7" mdbook-linkcheck
|
||||
- name: Clean website
|
||||
run: cd documentation/dev-portal && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/dev-portal && mdbook build
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "documentation/dev-portal/book/html/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/dev-portal-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ci-dev
|
||||
NYM_PROJECT_NAME: "Dev portal CI"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "dev-portal-${{ 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_DEVP }}"
|
||||
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
|
||||
@@ -1,7 +1,6 @@
|
||||
name: CI docs
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches-ignore: master
|
||||
paths:
|
||||
@@ -28,27 +27,29 @@ jobs:
|
||||
command: build
|
||||
args: --workspace --release --all
|
||||
- name: Install mdbook
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
|
||||
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
|
||||
- name: Install mdbook plugins
|
||||
run: |
|
||||
cargo install --vers "=0.2.2" mdbook-variables && cargo install \
|
||||
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
|
||||
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
|
||||
&& cargo install --vers "^0.7.7" mdbook-linkcheck
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
run: cd documentation && ./build_all_to_dist.sh
|
||||
continue-on-error: false
|
||||
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
|
||||
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
|
||||
cargo install --vers "^0.5.0" mdbook-cmdrun
|
||||
- name: Clean website
|
||||
run: cd documentation/docs && mdbook clean
|
||||
- name: Build website
|
||||
run: cd documentation/docs && mdbook build
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "dist/docs/"
|
||||
SOURCE: "documentation/docs/book/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/node_modules/"
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
name: Nym Connect - mobile (Rust)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "nym-connect/mobile/src-tauri/**"
|
||||
- "nym-connect/mobile/src-tauri/Cargo.toml"
|
||||
- "!nym-connect/mobile/src-tauri/gen/**"
|
||||
- "clients/client-core/**"
|
||||
- "clients/socks5/**"
|
||||
- "common/**"
|
||||
- "gateway/gateway-requests/**"
|
||||
- "contracts/vesting/**"
|
||||
- "nym-api/nym-api-requests/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "nym-connect/mobile/src-tauri/**"
|
||||
- "nym-connect/mobile/src-tauri/Cargo.toml"
|
||||
- "!nym-connect/mobile/src-tauri/gen/**"
|
||||
- "clients/client-core/**"
|
||||
- "clients/socks5/**"
|
||||
- "common/**"
|
||||
- "gateway/gateway-requests/**"
|
||||
- "contracts/vesting/**"
|
||||
- "nym-api/nym-api-requests/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
#runs-on: [self-hosted, custom-linux]
|
||||
runs-on: ubuntu-22.04
|
||||
#env:
|
||||
#RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
#defaults:
|
||||
#run:
|
||||
#working-directory: nym-connect/mobile/src-tauri/
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install \
|
||||
libwebkit2gtk-4.1-dev \
|
||||
build-essential \
|
||||
curl \
|
||||
wget \
|
||||
libssl-dev \
|
||||
libgtk-3-dev \
|
||||
squashfs-tools \
|
||||
libayatana-appindicator3-dev \
|
||||
librsvg2-dev \
|
||||
libsoup-3.0-dev \
|
||||
libjavascriptcoregtk-4.1-dev
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: stable
|
||||
components: clippy, rustfmt
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --manifest-path nym-connect/mobile/src-tauri/Cargo.toml -- --check
|
||||
|
||||
- name: Build all binaries
|
||||
run: cargo build --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
|
||||
|
||||
- name: Run all tests
|
||||
run: cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-targets -- -D warnings
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.69.0
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
@@ -48,12 +48,12 @@ jobs:
|
||||
RUSTFLAGS: '-C link-arg=-s'
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown
|
||||
args: --manifest-path contracts/Cargo.toml --workspace --target wasm32-unknown-unknown
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --lib --manifest-path contracts/Cargo.toml
|
||||
args: --manifest-path contracts/Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -64,4 +64,4 @@ jobs:
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
|
||||
args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
|
||||
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##nym-connect-}" && semver="${semver##v}"
|
||||
echo "version=${semver}" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_${semver}_x64.dmg " >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_${version}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/dmg/nym-connect_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
|
||||
@@ -85,9 +85,8 @@ jobs:
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##nym-connect-}" && semver="${semver##v}"
|
||||
echo "version=${semver}" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_${semver}_amd64.AppImage" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_${version}_amd64.AppImage" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/appimage/nym-connect_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##nym-connect-}" && semver="${semver##v}"
|
||||
echo "version=${semver}" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_${semver}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-connect_${version}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/msi/nym-connect_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##nym-wallet-}" && semver="${semver##v}"
|
||||
echo "version=${semver}" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_${semver}_x64.dmg" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_${version}_x64.dmg" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/dmg/nym-wallet_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##nym-wallet-}" && semver="${semver##v}"
|
||||
echo "version=${semver}" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_${semver}_amd64.AppImage" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_${version}_amd64.AppImage" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/appimage/nym-wallet_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
ref=${{ github.ref_name }}
|
||||
semver="${ref##nym-wallet-}" && semver="${semver##v}"
|
||||
echo "version=${semver}" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_${semver}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "filename=nym-wallet_${version}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
|
||||
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/msi/nym-wallet_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
push-release-data:
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
name: Typescript SDK docs
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "sdk/typescript/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "sdk/typescript/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install
|
||||
run: yarn
|
||||
- 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
|
||||
@@ -7,6 +7,8 @@ on:
|
||||
- "sdk/typescript/**"
|
||||
- "nym-connect/desktop/src/**"
|
||||
- "nym-connect/desktop/package.json"
|
||||
- "nym-connect/mobile/src/**"
|
||||
- "nym-connect/mobile/package.json"
|
||||
- "nym-wallet/src/**"
|
||||
- "nym-wallet/package.json"
|
||||
- "explorer/**"
|
||||
@@ -16,6 +18,8 @@ on:
|
||||
- "sdk/typescript/**"
|
||||
- "nym-connect/desktop/src/**"
|
||||
- "nym-connect/desktop/package.json"
|
||||
- "nym-connect/mobile/src/**"
|
||||
- "nym-connect/mobile/package.json"
|
||||
- "nym-wallet/src/**"
|
||||
- "nym-wallet/package.json"
|
||||
- "explorer/**"
|
||||
|
||||
@@ -4,55 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.28] (2023-08-22)
|
||||
|
||||
- [final step3]: add [rust] support to nyxd client in wasm ([#3743])
|
||||
- Feature/ephemera upgrade ([#3791])
|
||||
- [rust-sdk] feat: make it more convenient to send and receive messages in different tasks ([#3756])
|
||||
- feat: validator client refactoring + wasm compatible nyxd client ([#3726])
|
||||
- feat: retain connection between client init and run ([#3767])
|
||||
|
||||
[#3743]: https://github.com/nymtech/nym/issues/3743
|
||||
[#3791]: https://github.com/nymtech/nym/pull/3791
|
||||
[#3756]: https://github.com/nymtech/nym/pull/3756
|
||||
[#3726]: https://github.com/nymtech/nym/pull/3726
|
||||
[#3767]: https://github.com/nymtech/nym/pull/3767
|
||||
|
||||
|
||||
## [1.1.27] (2023-08-16)
|
||||
|
||||
- fix serialisation of contract types ([#3752])
|
||||
- Investigate spending credentials from the main API (coconut enabled to a gateway) from feature/ephemera branch ([#3741])
|
||||
- NymConnect UI stuck in showing "Gateway has issues" ([#3594])
|
||||
- [UPDATE] Update MiniBolt community-applications-and-guides dev docs ([#3754])
|
||||
|
||||
[#3752]: https://github.com/nymtech/nym/issues/3752
|
||||
[#3741]: https://github.com/nymtech/nym/issues/3741
|
||||
[#3594]: https://github.com/nymtech/nym/issues/3594
|
||||
[#3754]: https://github.com/nymtech/nym/pull/3754
|
||||
|
||||
## [v1.1.24] (2023-08-08)
|
||||
|
||||
- Latency based gateway selection is serial and slow ([#3710])
|
||||
- Network-requester: strip comments from allow lists ([#3625])
|
||||
- Remove (or start maintaining) `upgrade` commands from all binaries ([#3600])
|
||||
- Set sphinx as default packet type ([#3748])
|
||||
- Apply fix from feature/ephemera to develop too (#3698) ([#3742])
|
||||
- Feature/coco demos ([#3732])
|
||||
- Add updates to community list projects ([#3722])
|
||||
- Add geo-aware mixnet topology provider ([#3713])
|
||||
- Add updates to community list projects ([#3711])
|
||||
|
||||
[#3710]: https://github.com/nymtech/nym/issues/3710
|
||||
[#3625]: https://github.com/nymtech/nym/issues/3625
|
||||
[#3600]: https://github.com/nymtech/nym/issues/3600
|
||||
[#3748]: https://github.com/nymtech/nym/pull/3748
|
||||
[#3742]: https://github.com/nymtech/nym/pull/3742
|
||||
[#3732]: https://github.com/nymtech/nym/pull/3732
|
||||
[#3722]: https://github.com/nymtech/nym/pull/3722
|
||||
[#3713]: https://github.com/nymtech/nym/pull/3713
|
||||
[#3711]: https://github.com/nymtech/nym/pull/3711
|
||||
|
||||
## [v1.1.23] (2023-07-04)
|
||||
|
||||
- nym-cli: add client identity key signing support ([#3576])
|
||||
|
||||
Generated
+749
-3702
File diff suppressed because it is too large
Load Diff
+13
-24
@@ -34,7 +34,6 @@ members = [
|
||||
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
"common/cosmwasm-smart-contracts/ephemera",
|
||||
"common/cosmwasm-smart-contracts/group-contract",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||
@@ -75,7 +74,6 @@ members = [
|
||||
"common/types",
|
||||
"common/wasm-utils",
|
||||
"explorer-api",
|
||||
"explorer-api/explorer-api-requests",
|
||||
"gateway",
|
||||
"gateway/gateway-requests",
|
||||
"integrations/bity",
|
||||
@@ -119,39 +117,30 @@ anyhow = "1.0.71"
|
||||
async-trait = "0.1.64"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
cfg-if = "1.0.0"
|
||||
cosmwasm-derive = "=1.3.0"
|
||||
cosmwasm-schema = "=1.3.0"
|
||||
cosmwasm-std = "=1.3.0"
|
||||
# use 0.5.0 as that's the version used by cosmwasm-std 1.3.0
|
||||
# (and ideally we don't want to pull the same dependency twice)
|
||||
serde-json-wasm = "=0.5.0"
|
||||
cosmwasm-storage = "=1.3.0"
|
||||
cosmrs = "=0.14.0"
|
||||
# same version as used by cosmrs
|
||||
cosmwasm-derive = "=1.2.5"
|
||||
cosmwasm-schema = "=1.2.5"
|
||||
cosmwasm-std = "=1.2.5"
|
||||
cosmwasm-storage = "=1.2.5"
|
||||
cosmrs = "=0.8.0"
|
||||
cw-utils = "=1.0.1"
|
||||
cw-storage-plus = "=1.1.0"
|
||||
cw2 = { version = "=1.1.0" }
|
||||
cw3 = { version = "=1.1.0" }
|
||||
cw4 = { version = "=1.1.0" }
|
||||
cw-controllers = { version = "=1.1.0" }
|
||||
cw-storage-plus = "=1.0.1"
|
||||
cw2 = { version = "=1.0.1" }
|
||||
cw3 = { version = "=1.0.1" }
|
||||
cw3-fixed-multisig = { version = "=1.0.1" }
|
||||
cw4 = { version = "=1.0.1" }
|
||||
cw-controllers = { version = "=1.0.1" }
|
||||
dotenvy = "0.15.6"
|
||||
futures = "0.3.28"
|
||||
generic-array = "0.14.7"
|
||||
k256 = "0.11"
|
||||
getrandom = "0.2.10"
|
||||
k256 = "0.13"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
rand = "0.8.5"
|
||||
reqwest = "0.11.18"
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.91"
|
||||
tap = "1.0.1"
|
||||
tendermint-rpc = "0.32" # same version as used by cosmrs
|
||||
thiserror = "1.0.38"
|
||||
tokio = "1.24.1"
|
||||
url = "2.4"
|
||||
url = "2.2"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
# wasm-related dependencies
|
||||
wasmtimer = "0.2.0"
|
||||
|
||||
@@ -73,7 +73,7 @@ endef
|
||||
# Generate targets for the various cargo workspaces
|
||||
|
||||
$(eval $(call add_cargo_workspace,main,.))
|
||||
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown))
|
||||
$(eval $(call add_cargo_workspace,contracts,contracts,--target wasm32-unknown-unknown))
|
||||
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
|
||||
$(eval $(call add_cargo_workspace,wallet,nym-wallet,))
|
||||
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
|
||||
@@ -104,7 +104,7 @@ NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
|
||||
wasm: wasm-build wasm-opt
|
||||
|
||||
wasm-build:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --lib --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
|
||||
wasm-opt:
|
||||
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
|
||||
@@ -112,9 +112,6 @@ wasm-opt:
|
||||
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
|
||||
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
|
||||
|
||||
contract-schema:
|
||||
$(MAKE) -C contracts schema
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Misc
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -21,5 +21,5 @@ nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-bin-common = { path = "../../common/bin-common"}
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
use crate::error::Result;
|
||||
use bip39::Mnemonic;
|
||||
use nym_network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||
use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient;
|
||||
use nym_validator_client::nyxd::{self, DirectSigningHttpRpcNyxdClient};
|
||||
use nym_validator_client::nyxd::{Coin, Fee, NyxdClient};
|
||||
use nym_validator_client::nyxd;
|
||||
use nym_validator_client::nyxd::traits::CoconutBandwidthSigningClient;
|
||||
use nym_validator_client::nyxd::{Coin, DirectSigningNyxdClient, Fee, NyxdClient};
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) struct Client {
|
||||
nyxd_client: DirectSigningHttpRpcNyxdClient,
|
||||
nyxd_client: NyxdClient<DirectSigningNyxdClient>,
|
||||
mix_denom_base: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use log::*;
|
||||
use nym_bandwidth_controller::acquire::state::State;
|
||||
use nym_bin_common::completions::ArgShell;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::recovery_storage::RecoveryStorage;
|
||||
|
||||
@@ -17,9 +17,9 @@ use std::time::{Duration, SystemTime};
|
||||
use clap::{CommandFactory, Parser};
|
||||
use nym_bin_common::logging::setup_logging;
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::{Coin, Config};
|
||||
use nym_validator_client::DirectSigningHttpRpcNyxdClient;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
|
||||
use nym_validator_client::Config;
|
||||
|
||||
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
|
||||
|
||||
@@ -34,11 +34,11 @@ struct Cli {
|
||||
pub(crate) command: Command,
|
||||
}
|
||||
|
||||
async fn block_until_coconut_is_available<C: DkgQueryClient + Send + Sync>(
|
||||
client: &C,
|
||||
async fn block_until_coconut_is_available<C: CosmWasmClient + Send + Sync>(
|
||||
client: &nym_validator_client::Client<C>,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let epoch = client.get_current_epoch().await?;
|
||||
let epoch = client.nyxd.get_current_epoch().await?;
|
||||
let current_timestamp_secs = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)?
|
||||
.as_secs();
|
||||
@@ -89,18 +89,15 @@ async fn main() -> Result<()> {
|
||||
r.amount as u128,
|
||||
network_details.chain_details.mix_denom.base,
|
||||
);
|
||||
let endpoint = network_details.endpoints[0].nyxd_url.as_str();
|
||||
let client = DirectSigningHttpRpcNyxdClient::connect_with_mnemonic(
|
||||
config,
|
||||
endpoint,
|
||||
r.mnemonic.parse().unwrap(),
|
||||
)?;
|
||||
let client =
|
||||
nym_validator_client::Client::new_signing(config, r.mnemonic.parse().unwrap())?;
|
||||
|
||||
block_until_coconut_is_available(&client).await?;
|
||||
info!("Starting depositing funds, don't kill the process");
|
||||
|
||||
if !r.recovery_mode {
|
||||
let state = nym_bandwidth_controller::acquire::deposit(&client, amount).await?;
|
||||
let state =
|
||||
nym_bandwidth_controller::acquire::deposit(&client.nyxd, amount).await?;
|
||||
if nym_bandwidth_controller::acquire::get_credential(
|
||||
&state,
|
||||
&client,
|
||||
@@ -120,7 +117,7 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
recover_credentials(&client, &recovery_storage, &shared_storage).await?;
|
||||
recover_credentials(&client.nyxd, &recovery_storage, &shared_storage).await?;
|
||||
}
|
||||
}
|
||||
Command::Completions(c) => c.generate(&mut Cli::command(), bin_name),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.26"
|
||||
version = "1.1.23"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -14,11 +14,11 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# dependencies to review:
|
||||
futures = { workspace = true } # bunch of futures stuff, however, now that I think about it, it could perhaps be completely removed
|
||||
futures = "0.3" # bunch of futures stuff, however, now that I think about it, it could perhaps be completely removed
|
||||
# the AsyncRead, AsyncWrite, Stream, Sink, etc. traits could be used from tokio
|
||||
# channels should really be replaced with crossbeam due to that implementation being more efficient
|
||||
# and the single instance of abortable we have should really be refactored anyway
|
||||
url = { workspace = true }
|
||||
url = "2.2"
|
||||
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
dirs = "4.0"
|
||||
@@ -28,7 +28,7 @@ pretty_env_logger = "0.4" # for formatting log messages
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
thiserror = "1.0.34"
|
||||
tap = "1.0.1"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } # async runtime
|
||||
tokio-tungstenite = "0.14" # websocket
|
||||
@@ -48,7 +48,7 @@ nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
nym-client-websocket-requests = { path = "websocket-requests" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -19,7 +19,8 @@ use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
use nym_validator_client::QueryHttpRpcNyxdClient;
|
||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||
use nym_validator_client::Client;
|
||||
use std::error::Error;
|
||||
use tokio::sync::watch::error::SendError;
|
||||
|
||||
@@ -28,7 +29,7 @@ pub use nym_sphinx::receiver::ReconstructedMessage;
|
||||
|
||||
pub mod config;
|
||||
|
||||
type NativeClientBuilder<'a> = BaseClientBuilder<'a, QueryHttpRpcNyxdClient, OnDiskPersistent>;
|
||||
type NativeClientBuilder<'a> = BaseClientBuilder<'a, Client<QueryNyxdClient>, OnDiskPersistent>;
|
||||
|
||||
pub struct SocketClient {
|
||||
/// Client configuration options, including, among other things, packet sending rates,
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Args;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct BuildInfo {
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: BuildInfo) {
|
||||
println!("{}", args.output.format(&bin_info_owned!()))
|
||||
}
|
||||
@@ -174,15 +174,14 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let init_details = nym_client_core::init::setup_gateway(
|
||||
gateway_setup,
|
||||
&gateway_setup,
|
||||
&key_store,
|
||||
&details_store,
|
||||
register_gateway,
|
||||
Some(&config.base.client.nym_api_urls),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?
|
||||
.details;
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
|
||||
|
||||
let config_save_location = config.default_location();
|
||||
config.save_to_default_location().tap_err(|_| {
|
||||
|
||||
@@ -10,7 +10,7 @@ use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
@@ -22,12 +22,12 @@ use nym_config::OptionalSet;
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
pub(crate) mod build_info;
|
||||
pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
|
||||
pub static ref PRETTY_BUILD_INFORMATION: String =
|
||||
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
|
||||
}
|
||||
|
||||
// Helper for passing LONG_VERSION to clap
|
||||
@@ -42,10 +42,6 @@ pub(crate) struct Cli {
|
||||
#[clap(short, long)]
|
||||
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
||||
|
||||
/// Flag used for disabling the printed banner in tty.
|
||||
#[clap(long)]
|
||||
pub(crate) no_banner: bool,
|
||||
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
@@ -58,9 +54,6 @@ pub(crate) enum Commands {
|
||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||
Run(run::Run),
|
||||
|
||||
/// Show build information of this binary
|
||||
BuildInfo(build_info::BuildInfo),
|
||||
|
||||
/// Generate shell completions
|
||||
Completions(ArgShell),
|
||||
|
||||
@@ -80,13 +73,12 @@ pub(crate) struct OverrideConfig {
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let bin_name = "nym-native-client";
|
||||
|
||||
match args.command {
|
||||
Commands::Init(m) => init::execute(&m).await?,
|
||||
Commands::Run(m) => run::execute(&m).await?,
|
||||
Commands::BuildInfo(m) => build_info::execute(m),
|
||||
match &args.command {
|
||||
Commands::Init(m) => init::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
|
||||
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
|
||||
}
|
||||
|
||||
@@ -14,13 +14,10 @@ pub mod websocket;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
setup_logging();
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
|
||||
let args = commands::Cli::parse();
|
||||
setup_env(args.config_env_file.as_ref());
|
||||
|
||||
if !args.no_banner {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
setup_logging();
|
||||
|
||||
commands::execute(args).await
|
||||
commands::execute(&args).await
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.26"
|
||||
version = "1.1.23"
|
||||
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"
|
||||
@@ -14,9 +14,9 @@ pretty_env_logger = "0.4"
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
tap = "1.0.1"
|
||||
thiserror = { workspace = true }
|
||||
thiserror = "1.0.34"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
||||
url = { workspace = true }
|
||||
url = "2.2"
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Args;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct BuildInfo {
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: BuildInfo) {
|
||||
println!("{}", args.output.format(&bin_info_owned!()))
|
||||
}
|
||||
@@ -94,7 +94,6 @@ impl From<Init> for OverrideConfig {
|
||||
use_anonymous_replies: init_config.use_reply_surbs,
|
||||
fastmode: init_config.fastmode,
|
||||
no_cover: init_config.no_cover,
|
||||
geo_routing: None,
|
||||
medium_toggle: false,
|
||||
nyxd_urls: init_config.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||
@@ -186,15 +185,14 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let init_details = nym_client_core::init::setup_gateway(
|
||||
gateway_setup,
|
||||
&gateway_setup,
|
||||
&key_store,
|
||||
&details_store,
|
||||
register_gateway,
|
||||
Some(&config.core.base.client.nym_api_urls),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?
|
||||
.details;
|
||||
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
|
||||
|
||||
// TODO: ask the service provider we specified for its interface version and set it in the config
|
||||
|
||||
|
||||
@@ -10,25 +10,24 @@ use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use nym_client_core::config::{GatewayEndpointConfig, TopologyStructure};
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use std::error::Error;
|
||||
|
||||
pub(crate) mod build_info;
|
||||
pub mod init;
|
||||
pub(crate) mod run;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
|
||||
pub static ref PRETTY_BUILD_INFORMATION: String =
|
||||
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
|
||||
}
|
||||
|
||||
// Helper for passing LONG_VERSION to clap
|
||||
@@ -43,10 +42,6 @@ pub(crate) struct Cli {
|
||||
#[clap(short, long)]
|
||||
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
||||
|
||||
/// Flag used for disabling the printed banner in tty.
|
||||
#[clap(long)]
|
||||
pub(crate) no_banner: bool,
|
||||
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
@@ -59,9 +54,6 @@ pub(crate) enum Commands {
|
||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||
Run(run::Run),
|
||||
|
||||
/// Show build information of this binary
|
||||
BuildInfo(build_info::BuildInfo),
|
||||
|
||||
/// Generate shell completions
|
||||
Completions(ArgShell),
|
||||
|
||||
@@ -76,20 +68,18 @@ pub(crate) struct OverrideConfig {
|
||||
use_anonymous_replies: Option<bool>,
|
||||
fastmode: bool,
|
||||
no_cover: bool,
|
||||
geo_routing: Option<CountryGroup>,
|
||||
medium_toggle: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
outfox: bool,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let bin_name = "nym-socks5-client";
|
||||
|
||||
match args.command {
|
||||
Commands::Init(m) => init::execute(&m).await?,
|
||||
Commands::Run(m) => run::execute(&m).await?,
|
||||
Commands::BuildInfo(m) => build_info::execute(m),
|
||||
match &args.command {
|
||||
Commands::Init(m) => init::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
|
||||
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
|
||||
}
|
||||
@@ -101,13 +91,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
|
||||
let no_per_hop_delays = args.medium_toggle;
|
||||
|
||||
let topology_structure = if args.medium_toggle || args.geo_routing.is_some() {
|
||||
// TODO: rethink the default group. I just picked one for now.
|
||||
TopologyStructure::GeoAware(args.geo_routing.unwrap_or(CountryGroup::Europe))
|
||||
} else {
|
||||
TopologyStructure::default()
|
||||
};
|
||||
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
@@ -131,10 +114,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
// NOTE: see comment above about the order of the other disble cover traffic config
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseClientConfig::with_packet_type, packet_type)
|
||||
.with_base(
|
||||
BaseClientConfig::with_topology_structure,
|
||||
topology_structure,
|
||||
)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
.with_optional(Config::with_port, args.port)
|
||||
.with_optional_base_custom_env(
|
||||
|
||||
@@ -11,7 +11,6 @@ use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_socks5_client_core::NymClient;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
@@ -61,10 +60,6 @@ pub(crate) struct Run {
|
||||
#[clap(long, hide = true)]
|
||||
no_cover: bool,
|
||||
|
||||
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
|
||||
#[clap(long, hide = true, value_parser = validate_country_group)]
|
||||
geo_routing: Option<CountryGroup>,
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[clap(long, hide = true)]
|
||||
@@ -87,7 +82,6 @@ impl From<Run> for OverrideConfig {
|
||||
use_anonymous_replies: run_config.use_anonymous_replies,
|
||||
fastmode: run_config.fastmode,
|
||||
no_cover: run_config.no_cover,
|
||||
geo_routing: run_config.geo_routing,
|
||||
medium_toggle: run_config.medium_toggle,
|
||||
nyxd_urls: run_config.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||
@@ -96,13 +90,6 @@ impl From<Run> for OverrideConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_country_group(s: &str) -> Result<CountryGroup, String> {
|
||||
match s.parse() {
|
||||
Ok(cg) => Ok(cg),
|
||||
Err(_) => Err(format!("failed to parse country group: {}", s)),
|
||||
}
|
||||
}
|
||||
|
||||
// this only checks compatibility between config the binary. It does not take into consideration
|
||||
// network version. It might do so in the future.
|
||||
fn version_check(cfg: &Config) -> bool {
|
||||
|
||||
@@ -13,13 +13,10 @@ pub mod error;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
setup_logging();
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
|
||||
let args = commands::Cli::parse();
|
||||
setup_env(args.config_env_file.as_ref());
|
||||
|
||||
if !args.no_banner {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
setup_logging();
|
||||
|
||||
commands::execute(args).await
|
||||
commands::execute(&args).await
|
||||
}
|
||||
|
||||
Generated
+610
-764
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ name = "nym-client-wasm"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
version = "1.1.1"
|
||||
edition = "2021"
|
||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"]
|
||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/nymtech/nym"
|
||||
description = "A webassembly client which can be used to interact with the the Nym privacy platform. Wasm is used for Sphinx packet generation."
|
||||
@@ -33,7 +33,7 @@ wasm-bindgen-futures = "0.4"
|
||||
thiserror = "1.0.40"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
wasmtimer = { version = "0.2.0", features = ["tokio"] }
|
||||
wasm-timer = { git = "https://github.com/mmsinclair/wasm-timer", rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"}
|
||||
|
||||
# internal
|
||||
nym-node-tester-utils = { path = "../../common/node-tester-utils" }
|
||||
|
||||
@@ -246,7 +246,6 @@ impl From<TopologyWasm> for ConfigTopology {
|
||||
topology.topology_resolution_timeout_ms,
|
||||
),
|
||||
disable_refreshing: topology.disable_refreshing,
|
||||
topology_structure: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::storage::traits::FullWasmClientStorage;
|
||||
use crate::storage::ClientStorage;
|
||||
use crate::topology::WasmNymTopology;
|
||||
use js_sys::Promise;
|
||||
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
||||
use nym_client_core::client::base_client::{
|
||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||
};
|
||||
@@ -25,7 +26,6 @@ use nym_task::TaskManager;
|
||||
use nym_topology::provider_trait::{HardcodedTopologyProvider, TopologyProvider};
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use nym_validator_client::QueryReqwestRpcNyxdClient;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use std::sync::Arc;
|
||||
@@ -152,7 +152,7 @@ impl NymClientBuilder {
|
||||
let maybe_topology_provider = self.topology_provider();
|
||||
|
||||
let mut base_builder: BaseClientBuilder<_, FullWasmClientStorage> =
|
||||
BaseClientBuilder::<QueryReqwestRpcNyxdClient, _>::new(
|
||||
BaseClientBuilder::<FakeClient<DirectSigningNyxdClient>, _>::new(
|
||||
&self.config.base,
|
||||
storage,
|
||||
None,
|
||||
|
||||
@@ -8,7 +8,7 @@ use js_sys::Promise;
|
||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||
use nym_client_core::config;
|
||||
use nym_client_core::init::helpers::current_gateways;
|
||||
use nym_client_core::init::{setup_gateway_from, GatewaySetup, InitialisationResult};
|
||||
use nym_client_core::init::{setup_gateway_from, GatewaySetup, InitialisationDetails};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_topology::{gateway, NymTopology};
|
||||
@@ -82,14 +82,14 @@ async fn setup_gateway(
|
||||
client_store: &ClientStorage,
|
||||
chosen_gateway: Option<IdentityKey>,
|
||||
gateways: &[gateway::Node],
|
||||
) -> Result<InitialisationResult, WasmClientError> {
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
let setup = if client_store.has_full_gateway_info().await? {
|
||||
GatewaySetup::MustLoad
|
||||
} else {
|
||||
GatewaySetup::new_fresh(chosen_gateway.clone(), None)
|
||||
};
|
||||
|
||||
setup_gateway_from(setup, client_store, client_store, false, Some(gateways))
|
||||
setup_gateway_from(&setup, client_store, client_store, false, Some(gateways))
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
@@ -98,7 +98,7 @@ pub(crate) async fn setup_gateway_from_api(
|
||||
client_store: &ClientStorage,
|
||||
chosen_gateway: Option<IdentityKey>,
|
||||
nym_apis: &[Url],
|
||||
) -> Result<InitialisationResult, WasmClientError> {
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
let mut rng = thread_rng();
|
||||
let gateways = current_gateways(&mut rng, nym_apis).await?;
|
||||
setup_gateway(client_store, chosen_gateway, &gateways).await
|
||||
@@ -108,7 +108,7 @@ pub(crate) async fn setup_from_topology(
|
||||
explicit_gateway: Option<IdentityKey>,
|
||||
topology: &NymTopology,
|
||||
client_store: &ClientStorage,
|
||||
) -> Result<InitialisationResult, WasmClientError> {
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
let gateways = topology.gateways();
|
||||
setup_gateway(client_store, explicit_gateway, gateways).await
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use std::collections::HashSet;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::MutexGuard as AsyncMutexGuard;
|
||||
use wasm_utils::{console_error, console_log, console_warn};
|
||||
use wasmtimer::tokio::sleep;
|
||||
|
||||
pub(crate) struct EphemeralTestReceiver<'a> {
|
||||
sent_packets: u32,
|
||||
@@ -91,7 +90,7 @@ impl<'a> EphemeralTestReceiver<'a> {
|
||||
}
|
||||
|
||||
pub(crate) async fn perform_test(mut self) -> NodeTestResult {
|
||||
let mut timeout_fut = sleep(self.timeout_duration);
|
||||
let mut timeout_fut = wasm_timer::Delay::new(self.timeout_duration);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
|
||||
@@ -12,9 +12,10 @@ use crate::tester::helpers::{
|
||||
use crate::topology::WasmNymTopology;
|
||||
use futures::channel::mpsc;
|
||||
use js_sys::Promise;
|
||||
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core::client::key_manager::ManagedKeys;
|
||||
use nym_client_core::init::{InitialisationDetails, InitialisationResult};
|
||||
use nym_client_core::init::InitialisationDetails;
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_node_tester_utils::receiver::SimpleMessageReceiver;
|
||||
@@ -26,7 +27,6 @@ use nym_sphinx::preparer::PreparedFragment;
|
||||
use nym_task::TaskManager;
|
||||
use nym_topology::NymTopology;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use nym_validator_client::QueryReqwestRpcNyxdClient;
|
||||
use rand::rngs::OsRng;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
@@ -42,7 +42,7 @@ pub(crate) mod helpers;
|
||||
|
||||
pub type NodeTestMessage = TestMessage<WasmTestMessageExt>;
|
||||
type LockedGatewayClient =
|
||||
Arc<AsyncMutex<GatewayClient<QueryReqwestRpcNyxdClient, EphemeralStorage>>>;
|
||||
Arc<AsyncMutex<GatewayClient<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>>;
|
||||
|
||||
pub(crate) const DEFAULT_TEST_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
pub(crate) const DEFAULT_TEST_PACKETS: u32 = 20;
|
||||
@@ -78,7 +78,8 @@ pub struct NymNodeTesterBuilder {
|
||||
base_topology: NymTopology,
|
||||
|
||||
// unimplemented
|
||||
bandwidth_controller: Option<BandwidthController<QueryReqwestRpcNyxdClient, EphemeralStorage>>,
|
||||
bandwidth_controller:
|
||||
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
||||
}
|
||||
|
||||
fn address(keys: &ManagedKeys, gateway_identity: NodeIdentity) -> Recipient {
|
||||
@@ -129,9 +130,9 @@ impl NymNodeTesterBuilder {
|
||||
async fn gateway_info(
|
||||
&self,
|
||||
client_store: &ClientStorage,
|
||||
) -> Result<InitialisationResult, WasmClientError> {
|
||||
) -> Result<InitialisationDetails, WasmClientError> {
|
||||
if let Ok(loaded) = InitialisationDetails::try_load(client_store, client_store).await {
|
||||
Ok(loaded.into())
|
||||
Ok(loaded)
|
||||
} else {
|
||||
setup_from_topology(self.gateway.clone(), &self.base_topology, client_store).await
|
||||
}
|
||||
@@ -147,37 +148,26 @@ impl NymNodeTesterBuilder {
|
||||
};
|
||||
|
||||
let client_store = ClientStorage::new_async(&storage_id, None).await?;
|
||||
let initialisation_result = self.gateway_info(&client_store).await?;
|
||||
let init_details = initialisation_result.details;
|
||||
let managed_keys = init_details.managed_keys;
|
||||
|
||||
let init_details = self.gateway_info(&client_store).await?;
|
||||
let gateway_endpoint = init_details.gateway_details;
|
||||
let gateway_identity = gateway_endpoint.try_get_gateway_identity_key()?;
|
||||
let managed_keys = init_details.managed_keys;
|
||||
|
||||
let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded();
|
||||
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
||||
|
||||
let mut gateway_client =
|
||||
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
|
||||
existing_client.upgrade(
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
Duration::from_secs(10),
|
||||
self.bandwidth_controller.take(),
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
} else {
|
||||
GatewayClient::new(
|
||||
gateway_endpoint.gateway_listener,
|
||||
managed_keys.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(managed_keys.must_get_gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
Duration::from_secs(10),
|
||||
self.bandwidth_controller.take(),
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
};
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_endpoint.gateway_listener,
|
||||
managed_keys.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(managed_keys.must_get_gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
Duration::from_secs(10),
|
||||
self.bandwidth_controller.take(),
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
gateway_client.set_disabled_credentials_mode(true);
|
||||
gateway_client.authenticate_and_start().await?;
|
||||
|
||||
@@ -8,5 +8,5 @@ edition = "2021"
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
tokio = { workspace = true, features = ["time"] }
|
||||
futures = { workspace = true }
|
||||
futures = "0.3"
|
||||
notify = "5.1.0"
|
||||
|
||||
@@ -9,7 +9,7 @@ edition = "2021"
|
||||
bip39 = { workspace = true }
|
||||
rand = "0.7.3"
|
||||
thiserror = "1.0"
|
||||
url = { workspace = true }
|
||||
url = "2.2"
|
||||
|
||||
nym-coconut-interface = { path = "../coconut-interface" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
@@ -18,6 +18,7 @@ nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric"
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
|
||||
path = "../client-libs/validator-client"
|
||||
features = ["http-client"]
|
||||
features = ["nyxd-client"]
|
||||
|
||||
@@ -8,11 +8,11 @@ use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_network_defaults::VOUCHER_INFO;
|
||||
use nym_validator_client::coconut::all_coconut_api_clients;
|
||||
use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::traits::CoconutBandwidthSigningClient;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::tx::Hash;
|
||||
use nym_validator_client::nyxd::Coin;
|
||||
use nym_validator_client::nyxd::Hash;
|
||||
use nym_validator_client::CoconutApiClient;
|
||||
use rand::rngs::OsRng;
|
||||
use state::{KeyPair, State};
|
||||
use std::str::FromStr;
|
||||
@@ -21,7 +21,7 @@ pub mod state;
|
||||
|
||||
pub async fn deposit<C>(client: &C, amount: Coin) -> Result<State, BandwidthControllerError>
|
||||
where
|
||||
C: CoconutBandwidthSigningClient + Sync,
|
||||
C: CoconutBandwidthSigningClient,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||
@@ -70,8 +70,7 @@ where
|
||||
.get_current_epoch_threshold()
|
||||
.await?
|
||||
.ok_or(BandwidthControllerError::NoThreshold)?;
|
||||
|
||||
let coconut_api_clients = all_coconut_api_clients(client, epoch_id).await?;
|
||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(client, epoch_id).await?;
|
||||
|
||||
let signature = obtain_aggregate_signature(
|
||||
&state.params,
|
||||
|
||||
@@ -6,18 +6,15 @@ use nym_credential_storage::error::StorageError;
|
||||
use nym_credentials::error::Error as CredentialsError;
|
||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use nym_validator_client::coconut::CoconutApiError;
|
||||
use nym_validator_client::error::ValidatorClientError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BandwidthControllerError {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[error("Nyxd error: {0}")]
|
||||
Nyxd(#[from] nym_validator_client::nyxd::error::NyxdError),
|
||||
|
||||
#[error("coconut api query failure: {0}")]
|
||||
CoconutApiError(#[from] CoconutApiError),
|
||||
|
||||
#[error("There was a credential storage error - {0}")]
|
||||
CredentialStorageError(Box<dyn std::error::Error + Send + Sync>),
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_validator_client::coconut::all_coconut_api_clients;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
|
||||
use std::str::FromStr;
|
||||
use {
|
||||
nym_coconut_interface::Base58,
|
||||
@@ -14,8 +14,17 @@ use {
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_mockups::DkgQueryClient;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod acquire;
|
||||
pub mod error;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub mod wasm_mockups;
|
||||
|
||||
pub struct BandwidthController<C, St> {
|
||||
storage: St,
|
||||
@@ -55,8 +64,12 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
||||
let epoch_id = u64::from_str(&bandwidth_credential.epoch_id)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
|
||||
let coconut_api_clients = all_coconut_api_clients(&self.client, epoch_id).await?;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let coconut_api_clients =
|
||||
nym_validator_client::CoconutApiClient::all_coconut_api_clients(&self.client, epoch_id)
|
||||
.await?;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let coconut_api_clients = vec![];
|
||||
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?;
|
||||
|
||||
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct DirectSigningNyxdClient {}
|
||||
|
||||
pub trait DkgQueryClient {}
|
||||
|
||||
// impl CosmWasmClient for DirectSigningNyxdClient {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Client<C> {
|
||||
_phantom: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<C> DkgQueryClient for Client<C> {}
|
||||
@@ -5,13 +5,9 @@
|
||||
// and be used by our smart contracts
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinaryBuildInformation {
|
||||
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
|
||||
pub binary_name: &'static str,
|
||||
|
||||
// VERGEN_BUILD_TIMESTAMP
|
||||
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
|
||||
pub build_timestamp: &'static str,
|
||||
@@ -47,9 +43,8 @@ pub struct BinaryBuildInformation {
|
||||
|
||||
impl BinaryBuildInformation {
|
||||
// explicitly require the build_version to be passed as it's binary specific
|
||||
pub const fn new(binary_name: &'static str, build_version: &'static str) -> Self {
|
||||
pub const fn new(build_version: &'static str) -> Self {
|
||||
BinaryBuildInformation {
|
||||
binary_name,
|
||||
build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"),
|
||||
build_version,
|
||||
commit_sha: env!("VERGEN_GIT_SHA"),
|
||||
@@ -63,7 +58,6 @@ impl BinaryBuildInformation {
|
||||
|
||||
pub fn to_owned(&self) -> BinaryBuildInformationOwned {
|
||||
BinaryBuildInformationOwned {
|
||||
binary_name: self.binary_name.to_owned(),
|
||||
build_timestamp: self.build_timestamp.to_owned(),
|
||||
build_version: self.build_version.to_owned(),
|
||||
commit_sha: self.commit_sha.to_owned(),
|
||||
@@ -76,15 +70,39 @@ impl BinaryBuildInformation {
|
||||
}
|
||||
|
||||
pub fn pretty_print(&self) -> String {
|
||||
self.to_owned().to_string()
|
||||
format!(
|
||||
r#"
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
"#,
|
||||
"Build Timestamp:",
|
||||
self.build_timestamp,
|
||||
"Build Version:",
|
||||
self.build_version,
|
||||
"Commit SHA:",
|
||||
self.commit_sha,
|
||||
"Commit Date:",
|
||||
self.commit_timestamp,
|
||||
"Commit Branch:",
|
||||
self.commit_branch,
|
||||
"rustc Version:",
|
||||
self.rustc_version,
|
||||
"rustc Channel:",
|
||||
self.rustc_channel,
|
||||
"cargo Profile:",
|
||||
self.cargo_profile,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BinaryBuildInformationOwned {
|
||||
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
|
||||
pub binary_name: String,
|
||||
|
||||
// VERGEN_BUILD_TIMESTAMP
|
||||
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
|
||||
pub build_timestamp: String,
|
||||
@@ -117,62 +135,3 @@ pub struct BinaryBuildInformationOwned {
|
||||
/// Provides the cargo profile that was used for the build, for example `debug`.
|
||||
pub cargo_profile: String,
|
||||
}
|
||||
|
||||
impl Display for BinaryBuildInformationOwned {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
r#"
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
{:<20}{}
|
||||
"#,
|
||||
"Binary Name:",
|
||||
self.binary_name,
|
||||
"Build Timestamp:",
|
||||
self.build_timestamp,
|
||||
"Build Version:",
|
||||
self.build_version,
|
||||
"Commit SHA:",
|
||||
self.commit_sha,
|
||||
"Commit Date:",
|
||||
self.commit_timestamp,
|
||||
"Commit Branch:",
|
||||
self.commit_branch,
|
||||
"rustc Version:",
|
||||
self.rustc_version,
|
||||
"rustc Channel:",
|
||||
self.rustc_channel,
|
||||
"cargo Profile:",
|
||||
self.cargo_profile,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// since this macro will get expanded at the callsite, it will pull in correct binary version
|
||||
#[macro_export]
|
||||
macro_rules! bin_info {
|
||||
() => {
|
||||
$crate::build_information::BinaryBuildInformation::new(
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bin_info_owned {
|
||||
() => {
|
||||
$crate::build_information::BinaryBuildInformation::new(
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
)
|
||||
.to_owned()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,29 +10,27 @@ rust-version = "1.66"
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
base64 = "0.21.2"
|
||||
dashmap = "5.4.0"
|
||||
dirs = "4.0"
|
||||
futures = { workspace = true }
|
||||
dashmap = "5.4.0"
|
||||
futures = "0.3"
|
||||
humantime-serde = "1.0"
|
||||
log = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
reqwest = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sha2 = "0.10.6"
|
||||
tap = "1.0.1"
|
||||
thiserror = "1.0.34"
|
||||
time = "0.3.17"
|
||||
tokio = { version = "1.24.1", features = ["macros"]}
|
||||
url = { version ="2.2", features = ["serde"] }
|
||||
tungstenite = { version = "0.13.0", default-features = false }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
tokio = { version = "1.24.1", features = ["macros"]}
|
||||
time = "0.3.17"
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-bandwidth-controller = { path = "../bandwidth-controller" }
|
||||
nym-config = { path = "../config" }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-explorer-api-requests = { path = "../../explorer-api/explorer-api-requests" }
|
||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
@@ -45,6 +43,10 @@ nym-task = { path = "../task" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
|
||||
path = "../client-libs/validator-client"
|
||||
features = ["nyxd-client"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||
version = "0.1.11"
|
||||
features = ["time"]
|
||||
@@ -67,9 +69,9 @@ version = "0.4"
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
||||
version = "0.2.83"
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-timer]
|
||||
git = "https://github.com/mmsinclair/wasm-timer"
|
||||
rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.gloo-timers]
|
||||
version = "0.2.4"
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::received_buffer::ReceivedBufferMessage;
|
||||
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
|
||||
use crate::client::base_client::storage::gateway_details::GatewayDetailsStore;
|
||||
use crate::client::base_client::storage::MixnetClientStorage;
|
||||
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::ManagedKeys;
|
||||
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController};
|
||||
use crate::client::real_messages_control;
|
||||
use crate::client::real_messages_control::RealMessagesController;
|
||||
@@ -23,9 +22,8 @@ use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
|
||||
use crate::client::topology_control::{
|
||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||
};
|
||||
use crate::config::{Config, DebugConfig};
|
||||
use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::init::{setup_gateway, GatewaySetup, InitialisationDetails, InitialisationResult};
|
||||
use crate::{config, spawn_future};
|
||||
use futures::channel::mpsc;
|
||||
use log::{debug, info};
|
||||
@@ -44,11 +42,18 @@ use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use std::sync::Arc;
|
||||
use tap::TapFallible;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||
|
||||
use crate::client::base_client::storage::gateway_details::GatewayDetailsStore;
|
||||
use crate::init::{setup_gateway, GatewaySetup, InitialisationDetails};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
pub mod non_wasm_helpers;
|
||||
|
||||
@@ -194,13 +199,16 @@ where
|
||||
|
||||
// note: do **NOT** make this method public as its only valid usage is from within `start_base`
|
||||
// because it relies on the crypto keys being already loaded
|
||||
fn mix_address(details: &InitialisationDetails) -> Recipient {
|
||||
fn mix_address(
|
||||
managed_keys: &ManagedKeys,
|
||||
gateway_config: &GatewayEndpointConfig,
|
||||
) -> Recipient {
|
||||
Recipient::new(
|
||||
*details.managed_keys.identity_public_key(),
|
||||
*details.managed_keys.encryption_public_key(),
|
||||
*managed_keys.identity_public_key(),
|
||||
*managed_keys.encryption_public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(&details.gateway_details.gateway_id).unwrap(),
|
||||
NodeIdentity::from_base58_string(&gateway_config.gateway_id).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -285,7 +293,8 @@ where
|
||||
|
||||
async fn start_gateway_client(
|
||||
config: &Config,
|
||||
initialisation_result: InitialisationResult,
|
||||
gateway_config: GatewayEndpointConfig,
|
||||
managed_keys: &ManagedKeys,
|
||||
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
@@ -295,39 +304,24 @@ where
|
||||
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
|
||||
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let managed_keys = initialisation_result.details.managed_keys;
|
||||
let gateway_address = gateway_config.gateway_listener.clone();
|
||||
let gateway_id = gateway_config.gateway_id;
|
||||
|
||||
let mut gateway_client =
|
||||
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
|
||||
existing_client.upgrade(
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
config.debug.gateway_connection.gateway_response_timeout,
|
||||
bandwidth_controller,
|
||||
shutdown,
|
||||
)
|
||||
} else {
|
||||
let gateway_config = initialisation_result.details.gateway_details;
|
||||
// TODO: in theory, at this point, this should be infallible
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
let gateway_address = gateway_config.gateway_listener.clone();
|
||||
let gateway_id = gateway_config.gateway_id;
|
||||
|
||||
// TODO: in theory, at this point, this should be infallible
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
GatewayClient::new(
|
||||
gateway_address,
|
||||
managed_keys.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(managed_keys.must_get_gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
config.debug.gateway_connection.gateway_response_timeout,
|
||||
bandwidth_controller,
|
||||
shutdown,
|
||||
)
|
||||
};
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway_address,
|
||||
managed_keys.identity_keypair(),
|
||||
gateway_identity,
|
||||
Some(managed_keys.must_get_gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
config.debug.gateway_connection.gateway_response_timeout,
|
||||
bandwidth_controller,
|
||||
shutdown,
|
||||
);
|
||||
|
||||
gateway_client.set_disabled_credentials_mode(config.client.disabled_credentials_mode);
|
||||
|
||||
@@ -345,20 +339,14 @@ where
|
||||
|
||||
fn setup_topology_provider(
|
||||
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
|
||||
provider_from_config: config::TopologyStructure,
|
||||
nym_api_urls: Vec<Url>,
|
||||
) -> Box<dyn TopologyProvider + Send + Sync> {
|
||||
// if no custom provider was ... provided ..., create one using nym-api
|
||||
custom_provider.unwrap_or_else(|| match provider_from_config {
|
||||
config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
|
||||
custom_provider.unwrap_or_else(|| {
|
||||
Box::new(NymApiTopologyProvider::new(
|
||||
nym_api_urls,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
)),
|
||||
config::TopologyStructure::GeoAware(group) => Box::new(GeoAwareTopologyProvider::new(
|
||||
nym_api_urls,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
group,
|
||||
)),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -450,23 +438,17 @@ where
|
||||
Ok(mem_store)
|
||||
}
|
||||
|
||||
async fn initialise_keys_and_gateway(
|
||||
setup_method: GatewaySetup,
|
||||
key_store: &S::KeyStore,
|
||||
details_store: &S::GatewayDetailsStore,
|
||||
overwrite_data: bool,
|
||||
validator_servers: Option<&[Url]>,
|
||||
) -> Result<InitialisationResult, ClientCoreError>
|
||||
async fn initialise_keys_and_gateway(&self) -> Result<InitialisationDetails, ClientCoreError>
|
||||
where
|
||||
<S::KeyStore as KeyStore>::StorageError: Sync + Send,
|
||||
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
|
||||
{
|
||||
setup_gateway(
|
||||
setup_method,
|
||||
key_store,
|
||||
details_store,
|
||||
overwrite_data,
|
||||
validator_servers,
|
||||
&self.setup_method,
|
||||
self.client_store.key_store(),
|
||||
self.client_store.gateway_details_store(),
|
||||
false,
|
||||
Some(&self.config.client.nym_api_urls),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -482,14 +464,9 @@ where
|
||||
info!("Starting nym client");
|
||||
|
||||
// derive (or load) client keys and gateway configuration
|
||||
let init_res = Self::initialise_keys_and_gateway(
|
||||
self.setup_method,
|
||||
self.client_store.key_store(),
|
||||
self.client_store.gateway_details_store(),
|
||||
false,
|
||||
Some(&self.config.client.nym_api_urls),
|
||||
)
|
||||
.await?;
|
||||
let details = self.initialise_keys_and_gateway().await?;
|
||||
let gateway_config = details.gateway_details;
|
||||
let managed_keys = details.managed_keys;
|
||||
|
||||
let (reply_storage_backend, credential_store) = self.client_store.into_runtime_stores();
|
||||
|
||||
@@ -523,15 +500,14 @@ where
|
||||
let (reply_controller_sender, reply_controller_receiver) =
|
||||
reply_controller::requests::new_control_channels();
|
||||
|
||||
let self_address = Self::mix_address(&init_res.details);
|
||||
let ack_key = init_res.details.managed_keys.ack_key();
|
||||
let encryption_keys = init_res.details.managed_keys.encryption_keypair();
|
||||
let self_address = Self::mix_address(&managed_keys, &gateway_config);
|
||||
|
||||
// the components are started in very specific order. Unless you know what you are doing,
|
||||
// do not change that.
|
||||
let gateway_client = Self::start_gateway_client(
|
||||
self.config,
|
||||
init_res,
|
||||
gateway_config,
|
||||
&managed_keys,
|
||||
bandwidth_controller,
|
||||
mixnet_messages_sender,
|
||||
ack_sender,
|
||||
@@ -545,10 +521,8 @@ where
|
||||
|
||||
let topology_provider = Self::setup_topology_provider(
|
||||
self.custom_topology_provider.take(),
|
||||
self.config.debug.topology.topology_structure,
|
||||
self.config.get_nym_api_endpoints(),
|
||||
);
|
||||
|
||||
Self::start_topology_refresher(
|
||||
topology_provider,
|
||||
self.config.debug.topology,
|
||||
@@ -558,7 +532,7 @@ where
|
||||
.await?;
|
||||
|
||||
Self::start_received_messages_buffer_controller(
|
||||
encryption_keys,
|
||||
managed_keys.encryption_keypair(),
|
||||
received_buffer_request_receiver,
|
||||
mixnet_messages_receiver,
|
||||
reply_storage.key_storage(),
|
||||
@@ -583,7 +557,7 @@ where
|
||||
|
||||
let controller_config = real_messages_control::Config::new(
|
||||
&self.config.debug,
|
||||
Arc::clone(&ack_key),
|
||||
managed_keys.ack_key(),
|
||||
self_address,
|
||||
);
|
||||
|
||||
@@ -610,7 +584,7 @@ where
|
||||
{
|
||||
Self::start_cover_traffic_stream(
|
||||
&self.config.debug,
|
||||
ack_key,
|
||||
managed_keys.ack_key(),
|
||||
self_address,
|
||||
shared_topology_accessor.clone(),
|
||||
message_sender,
|
||||
|
||||
@@ -10,8 +10,8 @@ use crate::error::ClientCoreError;
|
||||
use log::{error, info};
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_validator_client::nyxd;
|
||||
use nym_validator_client::QueryHttpRpcNyxdClient;
|
||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||
use nym_validator_client::Client;
|
||||
use std::path::Path;
|
||||
use std::{fs, io};
|
||||
use time::OffsetDateTime;
|
||||
@@ -104,38 +104,48 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
pub fn create_bandwidth_controller<St: CredentialStorage>(
|
||||
config: &Config,
|
||||
storage: St,
|
||||
) -> BandwidthController<QueryHttpRpcNyxdClient, St> {
|
||||
) -> BandwidthController<Client<QueryNyxdClient>, St> {
|
||||
let nyxd_url = config
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
|
||||
create_bandwidth_controller_with_urls(nyxd_url, storage)
|
||||
create_bandwidth_controller_with_urls(nyxd_url, api_url, storage)
|
||||
}
|
||||
|
||||
pub fn create_bandwidth_controller_with_urls<St: CredentialStorage>(
|
||||
nyxd_url: Url,
|
||||
nym_api_url: Url,
|
||||
storage: St,
|
||||
) -> BandwidthController<QueryHttpRpcNyxdClient, St> {
|
||||
let client = default_query_dkg_client(nyxd_url);
|
||||
) -> BandwidthController<Client<QueryNyxdClient>, St> {
|
||||
let client = default_query_dkg_client(nyxd_url, nym_api_url);
|
||||
|
||||
BandwidthController::new(storage, client)
|
||||
}
|
||||
|
||||
pub fn default_query_dkg_client_from_config(config: &Config) -> QueryHttpRpcNyxdClient {
|
||||
pub fn default_query_dkg_client_from_config(config: &Config) -> Client<QueryNyxdClient> {
|
||||
let nyxd_url = config
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
|
||||
default_query_dkg_client(nyxd_url)
|
||||
default_query_dkg_client(nyxd_url, api_url)
|
||||
}
|
||||
|
||||
pub fn default_query_dkg_client(nyxd_url: Url) -> QueryHttpRpcNyxdClient {
|
||||
pub fn default_query_dkg_client(nyxd_url: Url, nym_api_url: Url) -> Client<QueryNyxdClient> {
|
||||
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
||||
let client_config = nyxd::Config::try_from_nym_network_details(&details)
|
||||
let mut client_config = nym_validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
// overwrite env configuration with config URLs
|
||||
QueryHttpRpcNyxdClient::connect(client_config, nyxd_url.as_str())
|
||||
client_config = client_config.with_urls(nyxd_url, nym_api_url);
|
||||
nym_validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client")
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ use std::time::Duration;
|
||||
use tokio::sync::mpsc::error::TrySendError;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::{sleep, Sleep};
|
||||
use tokio::time;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::{sleep, Sleep};
|
||||
use wasm_timer;
|
||||
|
||||
pub struct LoopCoverTrafficStream<R>
|
||||
where
|
||||
@@ -39,7 +39,11 @@ where
|
||||
|
||||
/// Internal state, determined by `average_message_sending_delay`,
|
||||
/// used to keep track of when a next packet should be sent out.
|
||||
next_delay: Pin<Box<Sleep>>,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
next_delay: Pin<Box<time::Sleep>>,
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
next_delay: Pin<Box<wasm_timer::Delay>>,
|
||||
|
||||
/// Channel used for sending prepared nym packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
@@ -86,9 +90,17 @@ where
|
||||
|
||||
// The next interval value is `next_poisson_delay` after the one that just
|
||||
// yielded.
|
||||
let now = self.next_delay.deadline();
|
||||
let next = now + next_poisson_delay;
|
||||
self.next_delay.as_mut().reset(next);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let now = self.next_delay.deadline();
|
||||
let next = now + next_poisson_delay;
|
||||
self.next_delay.as_mut().reset(next);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
self.next_delay.as_mut().reset(next_poisson_delay);
|
||||
}
|
||||
|
||||
Poll::Ready(Some(()))
|
||||
}
|
||||
@@ -108,7 +120,11 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
) -> Self {
|
||||
let rng = OsRng;
|
||||
|
||||
let next_delay = Box::pin(sleep(Default::default()));
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let next_delay = Box::pin(time::sleep(Default::default()));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let next_delay = Box::pin(wasm_timer::Delay::new(Default::default()));
|
||||
|
||||
LoopCoverTrafficStream {
|
||||
ack_key,
|
||||
@@ -126,7 +142,12 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
}
|
||||
|
||||
fn set_next_delay(&mut self, amount: Duration) {
|
||||
let next_delay = Box::pin(sleep(amount));
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let next_delay = Box::pin(time::sleep(amount));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let next_delay = Box::pin(wasm_timer::Delay::new(amount));
|
||||
|
||||
self.next_delay = next_delay;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::time::Duration;
|
||||
use wasm_timer;
|
||||
|
||||
pub use wasmtimer::{std::Instant, tokio::*};
|
||||
pub use wasm_timer::*;
|
||||
pub type IntervalStream = gloo_timers::future::IntervalStream;
|
||||
|
||||
pub(crate) fn get_time_now() -> Instant {
|
||||
Instant::now()
|
||||
wasm_timer::Instant::now()
|
||||
}
|
||||
|
||||
pub(crate) fn new_interval_stream(polling_rate: Duration) -> IntervalStream {
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
|
||||
use crate::spawn_future;
|
||||
use log::*;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
|
||||
use nym_credential_storage::storage::Storage;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||
|
||||
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
||||
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
||||
|
||||
@@ -27,10 +27,9 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::{sleep, Sleep};
|
||||
|
||||
use tokio::time;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::{sleep, Sleep};
|
||||
use wasm_timer;
|
||||
|
||||
mod sending_delay_controller;
|
||||
|
||||
@@ -83,7 +82,11 @@ where
|
||||
|
||||
/// Internal state, determined by `average_message_sending_delay`,
|
||||
/// used to keep track of when a next packet should be sent out.
|
||||
next_delay: Option<Pin<Box<Sleep>>>,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
next_delay: Option<Pin<Box<time::Sleep>>>,
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
next_delay: Option<Pin<Box<wasm_timer::Delay>>>,
|
||||
|
||||
// To make sure we don't overload the mix_tx channel, we limit the rate we are pushing
|
||||
// messages.
|
||||
@@ -370,9 +373,17 @@ where
|
||||
|
||||
// The next interval value is `next_poisson_delay` after the one that just
|
||||
// yielded.
|
||||
let now = next_delay.deadline();
|
||||
let next = now + next_poisson_delay;
|
||||
next_delay.as_mut().reset(next);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let now = next_delay.deadline();
|
||||
let next = now + next_poisson_delay;
|
||||
next_delay.as_mut().reset(next);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
next_delay.as_mut().reset(next_poisson_delay);
|
||||
}
|
||||
|
||||
// On every iteration we get new messages from upstream. Given that these come bunched
|
||||
// in `Vec`, this ensures that on average we will fetch messages faster than we can
|
||||
@@ -410,7 +421,12 @@ where
|
||||
self.config.traffic.message_sending_average_delay,
|
||||
);
|
||||
|
||||
let next_delay = Box::pin(sleep(sampled));
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let next_delay = Box::pin(time::sleep(sampled));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let next_delay = Box::pin(wasm_timer::Delay::new(sampled));
|
||||
|
||||
self.next_delay = Some(next_delay);
|
||||
|
||||
Poll::Pending
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use log::{debug, error, info};
|
||||
use nym_explorer_api_requests::PrettyDetailedMixNodeBond;
|
||||
use nym_topology::{
|
||||
nym_topology_from_detailed,
|
||||
provider_trait::{async_trait, TopologyProvider},
|
||||
NymTopology,
|
||||
};
|
||||
use nym_validator_client::client::MixId;
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
const MIN_NODES_PER_LAYER: usize = 1;
|
||||
const EXPLORER_API_MIXNODES_URL: &str = "https://explorer.nymtech.net/api/v1/mix-nodes";
|
||||
|
||||
// TODO: create a explorer-api-client
|
||||
async fn fetch_mixnodes_from_explorer_api() -> Option<Vec<PrettyDetailedMixNodeBond>> {
|
||||
reqwest::get(EXPLORER_API_MIXNODES_URL)
|
||||
.await
|
||||
.ok()?
|
||||
.json::<Vec<PrettyDetailedMixNodeBond>>()
|
||||
.await
|
||||
.ok()
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum CountryGroup {
|
||||
Europe,
|
||||
NorthAmerica,
|
||||
SouthAmerica,
|
||||
Oceania,
|
||||
Asia,
|
||||
Africa,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
// We map contry codes into group, which initially are continent codes to a first approximation,
|
||||
// but we do it manually to reserve the right to tweak this distribution for our purposes.
|
||||
fn new(country_code: &str) -> Self {
|
||||
let country_code = country_code.to_uppercase();
|
||||
use CountryGroup::*;
|
||||
match country_code.as_ref() {
|
||||
// Europe
|
||||
"AT" => Europe,
|
||||
"BG" => Europe,
|
||||
"CH" => Europe,
|
||||
"CY" => Europe,
|
||||
"CZ" => Europe,
|
||||
"DE" => Europe,
|
||||
"DK" => Europe,
|
||||
"ES" => Europe,
|
||||
"FI" => Europe,
|
||||
"FR" => Europe,
|
||||
"GB" => Europe,
|
||||
"GR" => Europe,
|
||||
"IE" => Europe,
|
||||
"IT" => Europe,
|
||||
"LT" => Europe,
|
||||
"LU" => Europe,
|
||||
"LV" => Europe,
|
||||
"MD" => Europe,
|
||||
"MT" => Europe,
|
||||
"NL" => Europe,
|
||||
"NO" => Europe,
|
||||
"PL" => Europe,
|
||||
"RO" => Europe,
|
||||
"SE" => Europe,
|
||||
"SK" => Europe,
|
||||
"TR" => Europe,
|
||||
"UA" => Europe,
|
||||
|
||||
// North America
|
||||
"CA" => NorthAmerica,
|
||||
"MX" => NorthAmerica,
|
||||
"US" => NorthAmerica,
|
||||
|
||||
// South America
|
||||
"AR" => SouthAmerica,
|
||||
"BR" => SouthAmerica,
|
||||
"CL" => SouthAmerica,
|
||||
"CO" => SouthAmerica,
|
||||
"CR" => SouthAmerica,
|
||||
"GT" => SouthAmerica,
|
||||
|
||||
// Oceania
|
||||
"AU" => Oceania,
|
||||
|
||||
// Asia
|
||||
"AM" => Asia,
|
||||
"BH" => Asia,
|
||||
"CN" => Asia,
|
||||
"GE" => Asia,
|
||||
"HK" => Asia,
|
||||
"ID" => Asia,
|
||||
"IL" => Asia,
|
||||
"IN" => Asia,
|
||||
"JP" => Asia,
|
||||
"KH" => Asia,
|
||||
"KR" => Asia,
|
||||
"KZ" => Asia,
|
||||
"MY" => Asia,
|
||||
"RU" => Asia,
|
||||
"SG" => Asia,
|
||||
"TH" => Asia,
|
||||
"VN" => Asia,
|
||||
|
||||
// Africa
|
||||
"SC" => Africa,
|
||||
"UG" => Africa,
|
||||
"ZA" => Africa,
|
||||
|
||||
// And group level codes work too
|
||||
"EU" => Europe,
|
||||
"NA" => NorthAmerica,
|
||||
"SA" => SouthAmerica,
|
||||
"OC" => Oceania,
|
||||
"AS" => Asia,
|
||||
"AF" => Africa,
|
||||
|
||||
// And some aliases
|
||||
"EUROPE" => Europe,
|
||||
"NORTHAMERICA" => NorthAmerica,
|
||||
"SOUTHAMERICA" => SouthAmerica,
|
||||
"OCEANIA" => Oceania,
|
||||
"ASIA" => Asia,
|
||||
"AFRICA" => Africa,
|
||||
|
||||
_ => {
|
||||
info!("Unknown country code: {}", country_code);
|
||||
Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CountryGroup {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe => write!(f, "EU"),
|
||||
NorthAmerica => write!(f, "NA"),
|
||||
SouthAmerica => write!(f, "SA"),
|
||||
Oceania => write!(f, "OC"),
|
||||
Asia => write!(f, "AS"),
|
||||
Africa => write!(f, "AF"),
|
||||
Unknown => write!(f, "Unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for CountryGroup {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let group = CountryGroup::new(s);
|
||||
if group == CountryGroup::Unknown {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
#[allow(unused)]
|
||||
fn known(self) -> Option<CountryGroup> {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
|
||||
Unknown => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn group_mixnodes_by_country_code(
|
||||
mixnodes: Vec<PrettyDetailedMixNodeBond>,
|
||||
) -> HashMap<CountryGroup, Vec<MixId>> {
|
||||
mixnodes
|
||||
.into_iter()
|
||||
.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());
|
||||
let mixnodes = acc.entry(group_code).or_insert_with(Vec::new);
|
||||
mixnodes.push(m.mix_id);
|
||||
}
|
||||
acc
|
||||
})
|
||||
}
|
||||
|
||||
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
|
||||
let mixnode_distribution = mixnodes
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, v.len()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
debug!("Mixnode distribution - {}", mixnode_distribution);
|
||||
}
|
||||
|
||||
fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
|
||||
let mixes = topology.mixes();
|
||||
if mixes.keys().len() < 3 {
|
||||
error!("Layer is missing in topology!");
|
||||
return Err(());
|
||||
}
|
||||
for (layer, mixnodes) in mixes {
|
||||
debug!("Layer {:?} has {} mixnodes", layer, mixnodes.len());
|
||||
if mixnodes.len() < MIN_NODES_PER_LAYER {
|
||||
error!(
|
||||
"There are only {} mixnodes in layer {:?}",
|
||||
mixnodes.len(),
|
||||
layer
|
||||
);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct GeoAwareTopologyProvider {
|
||||
validator_client: nym_validator_client::client::NymApiClient,
|
||||
filter_on: CountryGroup,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl GeoAwareTopologyProvider {
|
||||
pub fn new(
|
||||
mut nym_api_urls: Vec<Url>,
|
||||
client_version: String,
|
||||
filter_on: CountryGroup,
|
||||
) -> GeoAwareTopologyProvider {
|
||||
log::info!(
|
||||
"Creating geo-aware topology provider with filter on {:?}",
|
||||
filter_on
|
||||
);
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
GeoAwareTopologyProvider {
|
||||
validator_client: nym_validator_client::client::NymApiClient::new(
|
||||
nym_api_urls[0].clone(),
|
||||
),
|
||||
filter_on,
|
||||
client_version,
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_topology(&self) -> Option<NymTopology> {
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
// Also fetch mixnodes cached by explorer-api, with the purpose of getting their
|
||||
// geolocation.
|
||||
debug!("Fetching mixnodes from explorer-api...");
|
||||
let Some(mixnodes_from_explorer_api) = fetch_mixnodes_from_explorer_api().await else {
|
||||
error!("failed to get mixnodes from explorer-api");
|
||||
return None;
|
||||
};
|
||||
|
||||
// Partition mixnodes_from_explorer_api according to the value of
|
||||
// two_letter_iso_country_code.
|
||||
// NOTE: we construct the full distribution here, but only use the one we're interested in.
|
||||
// The reason we this instead of a straight filter is that this opens up the possibility to
|
||||
// complement a small grouping with mixnodes from adjecent countries.
|
||||
let mixnode_distribution = group_mixnodes_by_country_code(mixnodes_from_explorer_api);
|
||||
log_mixnode_distribution(&mixnode_distribution);
|
||||
|
||||
let Some(filtered_mixnode_ids) = mixnode_distribution.get(&self.filter_on) else {
|
||||
error!("no mixnodes found for: {}", self.filter_on);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mixnodes = mixnodes
|
||||
.into_iter()
|
||||
.filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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()?;
|
||||
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl TopologyProvider for GeoAwareTopologyProvider {
|
||||
// this will be manually refreshed on a timer specified inside mixnet client config
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl TopologyProvider for GeoAwareTopologyProvider {
|
||||
// this will be manually refreshed on a timer specified inside mixnet client config
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_topology().await
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ use nym_topology::NymTopologyError;
|
||||
use std::time::Duration;
|
||||
|
||||
mod accessor;
|
||||
pub mod geo_aware_provider;
|
||||
pub(crate) mod nym_api_provider;
|
||||
|
||||
// TODO: move it to config later
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
use crate::{client::topology_control::geo_aware_provider::CountryGroup, error::ClientCoreError};
|
||||
use crate::error::ClientCoreError;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@@ -158,15 +158,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
|
||||
self.set_topology_structure(topology_structure);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
|
||||
self.debug.topology.topology_structure = topology_structure;
|
||||
}
|
||||
|
||||
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
|
||||
if no_per_hop_delays {
|
||||
self.set_no_per_hop_delays()
|
||||
@@ -475,16 +466,6 @@ pub struct Topology {
|
||||
/// the first valid instance.
|
||||
/// Supersedes `topology_refresh_rate_ms`.
|
||||
pub disable_refreshing: bool,
|
||||
|
||||
/// Specifies the mixnode topology to be used for sending packets.
|
||||
pub topology_structure: TopologyStructure,
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TopologyStructure {
|
||||
#[default]
|
||||
NymApi,
|
||||
GeoAware(CountryGroup),
|
||||
}
|
||||
|
||||
impl Default for Topology {
|
||||
@@ -493,7 +474,6 @@ impl Default for Topology {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
topology_structure: TopologyStructure::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,6 @@ impl From<TopologyV1_1_20_2> for Topology {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: value.disable_refreshing,
|
||||
topology_structure: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
use crate::config::GatewayEndpointConfig;
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::init::RegistrationResult;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::{debug, info, trace, warn};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_topology::{filter::VersionFilterable, gateway};
|
||||
use rand::{seq::SliceRandom, Rng};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
@@ -15,6 +15,8 @@ use tap::TapFallible;
|
||||
use tungstenite::Message;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_validator_client::nyxd::DirectSigningNyxdClient;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::net::TcpStream;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -25,20 +27,17 @@ use tokio_tungstenite::connect_async;
|
||||
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::sleep;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use nym_bandwidth_controller::wasm_mockups::DirectSigningNyxdClient;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_timer::Instant;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_utils::websocket::JSWebsocket;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::std::Instant;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::sleep;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
type WsConn = JSWebsocket;
|
||||
|
||||
const CONCURRENT_GATEWAYS_MEASURED: usize = 20;
|
||||
const MEASUREMENTS: usize = 3;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -125,9 +124,15 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
Ok::<(), ClientCoreError>(())
|
||||
};
|
||||
|
||||
let timeout = sleep(PING_TIMEOUT);
|
||||
// thanks to wasm we can't use tokio::time::timeout : (
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let timeout = tokio::time::sleep(PING_TIMEOUT);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::pin!(timeout);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut timeout = wasm_timer::Delay::new(PING_TIMEOUT);
|
||||
|
||||
tokio::select! {
|
||||
_ = &mut timeout => {
|
||||
warn!("timed out while trying to perform measurement...")
|
||||
@@ -153,29 +158,23 @@ pub(super) async fn choose_gateway_by_latency<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
info!(
|
||||
"choosing gateway by latency, pinging {} gateways ...",
|
||||
gateways.len()
|
||||
);
|
||||
info!("choosing gateway by latency...");
|
||||
|
||||
let gateways_with_latency = Arc::new(tokio::sync::Mutex::new(Vec::new()));
|
||||
futures::stream::iter(gateways)
|
||||
.for_each_concurrent(CONCURRENT_GATEWAYS_MEASURED, |gateway| async {
|
||||
let id = *gateway.identity();
|
||||
trace!("measuring latency to {id}...");
|
||||
match measure_latency(gateway).await {
|
||||
Ok(with_latency) => {
|
||||
debug!("{id}: {:?}", with_latency.latency);
|
||||
gateways_with_latency.lock().await.push(with_latency);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("failed to measure {id}: {err}");
|
||||
}
|
||||
};
|
||||
})
|
||||
.await;
|
||||
let mut gateways_with_latency = Vec::new();
|
||||
for gateway in gateways {
|
||||
let id = *gateway.identity();
|
||||
trace!("measuring latency to {id}...");
|
||||
let with_latency = match measure_latency(gateway).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
warn!("failed to measure {id}: {err}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
debug!("{id}: {:?}", with_latency.latency);
|
||||
gateways_with_latency.push(with_latency)
|
||||
}
|
||||
|
||||
let gateways_with_latency = gateways_with_latency.lock().await;
|
||||
let chosen = gateways_with_latency
|
||||
.choose_weighted(rng, |item| 1. / item.latency.as_secs_f32())
|
||||
.expect("invalid selection weight!");
|
||||
@@ -201,9 +200,9 @@ pub(super) fn uniformly_random_gateway<R: Rng>(
|
||||
pub(super) async fn register_with_gateway(
|
||||
gateway: &GatewayEndpointConfig,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Result<RegistrationResult, ClientCoreError> {
|
||||
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
let mut gateway_client: GatewayClient<DirectSigningNyxdClient, _> = GatewayClient::new_init(
|
||||
gateway.gateway_listener.clone(),
|
||||
gateway.try_get_gateway_identity_key()?,
|
||||
our_identity.clone(),
|
||||
@@ -217,8 +216,5 @@ pub(super) async fn register_with_gateway(
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.tap_err(|_| log::warn!("Failed to register with the gateway!"))?;
|
||||
Ok(RegistrationResult {
|
||||
shared_keys,
|
||||
authenticated_ephemeral_client: Some(gateway_client),
|
||||
})
|
||||
Ok(shared_keys)
|
||||
}
|
||||
|
||||
@@ -14,39 +14,16 @@ use crate::{
|
||||
error::ClientCoreError,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_client::client::InitOnly;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_sphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
||||
use nym_topology::gateway;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::Serialize;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
pub struct RegistrationResult {
|
||||
pub shared_keys: Arc<SharedKeys>,
|
||||
pub authenticated_ephemeral_client: Option<GatewayClient<InitOnly>>,
|
||||
}
|
||||
|
||||
pub struct InitialisationResult {
|
||||
pub details: InitialisationDetails,
|
||||
pub authenticated_ephemeral_client: Option<GatewayClient<InitOnly>>,
|
||||
}
|
||||
|
||||
impl From<InitialisationDetails> for InitialisationResult {
|
||||
fn from(details: InitialisationDetails) -> Self {
|
||||
InitialisationResult {
|
||||
details,
|
||||
authenticated_ephemeral_client: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rename to something better...
|
||||
#[derive(Debug)]
|
||||
pub struct InitialisationDetails {
|
||||
@@ -97,6 +74,7 @@ impl InitialisationDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum GatewaySetup {
|
||||
/// The gateway specification MUST BE loaded from the underlying storage.
|
||||
MustLoad,
|
||||
@@ -114,13 +92,6 @@ pub enum GatewaySetup {
|
||||
/// Full gateway configuration
|
||||
details: PersistedGatewayDetails,
|
||||
},
|
||||
ReuseConnection {
|
||||
/// The authenticated ephemeral client that was created during `init`
|
||||
authenticated_ephemeral_client: GatewayClient<InitOnly>,
|
||||
|
||||
/// Details of this pre-initialised client
|
||||
details: InitialisationDetails,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<PersistedGatewayDetails> for GatewaySetup {
|
||||
@@ -295,32 +266,18 @@ fn ensure_valid_details(
|
||||
}
|
||||
|
||||
pub async fn setup_gateway_from<K, D>(
|
||||
setup: GatewaySetup,
|
||||
setup: &GatewaySetup,
|
||||
key_store: &K,
|
||||
details_store: &D,
|
||||
overwrite_data: bool,
|
||||
gateways: Option<&[gateway::Node]>,
|
||||
) -> Result<InitialisationResult, ClientCoreError>
|
||||
) -> Result<InitialisationDetails, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
D: GatewayDetailsStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
// I don't like how we can't deal with this variant in the match below, but we need to take ownership of internal values.
|
||||
if let GatewaySetup::ReuseConnection {
|
||||
authenticated_ephemeral_client,
|
||||
details,
|
||||
} = setup
|
||||
{
|
||||
// if we have already performed the full setup, forward the details.
|
||||
// it's up to the caller to ensure persistence
|
||||
return Ok(InitialisationResult {
|
||||
details,
|
||||
authenticated_ephemeral_client: Some(authenticated_ephemeral_client),
|
||||
});
|
||||
}
|
||||
|
||||
let mut rng = OsRng;
|
||||
|
||||
// try load gateway details
|
||||
@@ -329,14 +286,14 @@ where
|
||||
// try load keys and decide what to do based on the GatewaySetup
|
||||
let mut managed_keys = match ManagedKeys::try_load(key_store).await {
|
||||
Ok(loaded_keys) => {
|
||||
match &setup {
|
||||
match setup {
|
||||
GatewaySetup::MustLoad => {
|
||||
// get EVERYTHING from the storage
|
||||
let details = loaded_details?;
|
||||
ensure_valid_details(&details, &loaded_keys)?;
|
||||
|
||||
// no need to persist anything as we got everything from the storage
|
||||
return Ok(InitialisationDetails::new(details.into(), loaded_keys).into());
|
||||
return Ok(InitialisationDetails::new(details.into(), loaded_keys));
|
||||
}
|
||||
GatewaySetup::Predefined { details } => {
|
||||
// we already have defined gateway details AND a shared key
|
||||
@@ -347,9 +304,10 @@ where
|
||||
_store_gateway_details(details_store, details).await?;
|
||||
}
|
||||
|
||||
return Ok(
|
||||
InitialisationDetails::new(details.clone().into(), loaded_keys).into(),
|
||||
);
|
||||
return Ok(InitialisationDetails::new(
|
||||
details.clone().into(),
|
||||
loaded_keys,
|
||||
));
|
||||
}
|
||||
GatewaySetup::Specified { gateway_identity } => {
|
||||
// if that data was already stored...
|
||||
@@ -365,8 +323,7 @@ where
|
||||
return Ok(InitialisationDetails::new(
|
||||
existing_gateway.into(),
|
||||
loaded_keys,
|
||||
)
|
||||
.into());
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,8 +341,7 @@ where
|
||||
return Ok(InitialisationDetails::new(
|
||||
existing_gateway.into(),
|
||||
loaded_keys,
|
||||
)
|
||||
.into());
|
||||
));
|
||||
}
|
||||
|
||||
// we didn't get full details from the store and we have loaded some keys
|
||||
@@ -396,9 +352,6 @@ where
|
||||
return Err(ClientCoreError::ForbiddenKeyOverwrite);
|
||||
}
|
||||
}
|
||||
GatewaySetup::ReuseConnection { .. } => {
|
||||
unreachable!("the reuse connection variant was already manually covered")
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
@@ -418,9 +371,7 @@ where
|
||||
let our_identity = managed_keys.identity_keypair();
|
||||
|
||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||
let registration_result =
|
||||
helpers::register_with_gateway(&gateway_details, our_identity).await?;
|
||||
let shared_keys = registration_result.shared_keys;
|
||||
let shared_keys = helpers::register_with_gateway(&gateway_details, our_identity).await?;
|
||||
|
||||
let persisted_details = PersistedGatewayDetails::new(gateway_details, &shared_keys);
|
||||
|
||||
@@ -435,19 +386,19 @@ where
|
||||
// persist gateway config
|
||||
_store_gateway_details(details_store, &persisted_details).await?;
|
||||
|
||||
Ok(InitialisationResult {
|
||||
details: InitialisationDetails::new(persisted_details.into(), managed_keys),
|
||||
authenticated_ephemeral_client: registration_result.authenticated_ephemeral_client,
|
||||
})
|
||||
Ok(InitialisationDetails::new(
|
||||
persisted_details.into(),
|
||||
managed_keys,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn setup_gateway<K, D>(
|
||||
setup: GatewaySetup,
|
||||
setup: &GatewaySetup,
|
||||
key_store: &K,
|
||||
details_store: &D,
|
||||
overwrite_data: bool,
|
||||
validator_servers: Option<&[Url]>,
|
||||
) -> Result<InitialisationResult, ClientCoreError>
|
||||
) -> Result<InitialisationDetails, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
D: GatewayDetailsStore,
|
||||
|
||||
@@ -9,10 +9,10 @@ edition = "2021"
|
||||
[dependencies]
|
||||
# TODO: (for this and other crates), similarly to 'tokio', import only required "futures" modules rather than
|
||||
# the entire crate
|
||||
futures = { workspace = true }
|
||||
futures = "0.3"
|
||||
log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
url = "2.2"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
tokio = { version = "1.24.1", features = ["macros"] }
|
||||
|
||||
@@ -25,7 +25,7 @@ nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
nym-pemstore = { path = "../../pemstore" }
|
||||
nym-validator-client = { path = "../validator-client", default-features = false }
|
||||
nym-validator-client = { path = "../validator-client" }
|
||||
nym-task = { path = "../../task" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
@@ -58,9 +58,9 @@ path = "../../wasm-utils"
|
||||
features = ["websocket"]
|
||||
|
||||
# only import it in wasm. Prefer proper tokio timer in non-wasm
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-timer]
|
||||
git = "https://github.com/mmsinclair/wasm-timer"
|
||||
rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"
|
||||
|
||||
# this is due to tungstenite using `rand` 0.8 and associated changes in `getrandom` crate
|
||||
# which now does not support wasm32-unknown-unknown target by default.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::GatewayClientError;
|
||||
@@ -22,7 +22,6 @@ use nym_gateway_requests::{BinaryRequest, ClientControlRequest, ServerResponse,
|
||||
use nym_network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_task::TaskClient;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use rand::rngs::OsRng;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
@@ -30,19 +29,21 @@ use std::time::Duration;
|
||||
use tungstenite::protocol::Message;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::sleep;
|
||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio_tungstenite::connect_async;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_utils::websocket::JSWebsocket;
|
||||
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::sleep;
|
||||
use wasm_timer;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_utils::websocket::JSWebsocket;
|
||||
|
||||
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
|
||||
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
||||
|
||||
pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
|
||||
pub struct GatewayClient<C, St> {
|
||||
authenticated: bool,
|
||||
disabled_credentials_mode: bool,
|
||||
bandwidth_remaining: i64,
|
||||
@@ -196,7 +197,16 @@ impl<C, St> GatewayClient<C, St> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
sleep(self.reconnection_backoff).await;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::time::sleep(self.reconnection_backoff).await;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Err(err) = wasm_timer::Delay::new(self.reconnection_backoff).await {
|
||||
error!(
|
||||
"the timer has gone away while in reconnection backoff! - {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// final attempt (done separately to be able to return a proper error)
|
||||
@@ -225,9 +235,16 @@ impl<C, St> GatewayClient<C, St> {
|
||||
_ => return Err(GatewayClientError::ConnectionInInvalidState),
|
||||
};
|
||||
|
||||
let timeout = sleep(self.response_timeout_duration);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let timeout = tokio::time::sleep(self.response_timeout_duration);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::pin!(timeout);
|
||||
|
||||
// technically the `wasm_timer` also works outside wasm, but unless required,
|
||||
// I really prefer to just stick to tokio
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut timeout = wasm_timer::Delay::new(self.response_timeout_duration);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = self.shutdown.recv() => {
|
||||
@@ -467,14 +484,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
pub async fn perform_initial_authentication(
|
||||
&mut self,
|
||||
) -> Result<Arc<SharedKeys>, GatewayClientError> {
|
||||
if self.authenticated {
|
||||
return if let Some(shared_key) = &self.shared_key {
|
||||
Ok(Arc::clone(shared_key))
|
||||
} else {
|
||||
Err(GatewayClientError::AuthenticationFailure)
|
||||
};
|
||||
}
|
||||
|
||||
if self.shared_key.is_some() {
|
||||
self.authenticate(None).await?;
|
||||
} else {
|
||||
@@ -759,9 +768,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InitOnly;
|
||||
|
||||
impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
impl<C> GatewayClient<C, EphemeralCredentialStorage> {
|
||||
// for initialisation we do not need credential storage. Though it's still a bit weird we have to set the generic...
|
||||
pub fn new_init(
|
||||
gateway_address: String,
|
||||
@@ -778,7 +785,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
let shutdown = TaskClient::dummy();
|
||||
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
|
||||
|
||||
GatewayClient {
|
||||
GatewayClient::<C, EphemeralCredentialStorage> {
|
||||
authenticated: false,
|
||||
disabled_credentials_mode: true,
|
||||
bandwidth_remaining: 0,
|
||||
@@ -796,37 +803,4 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
shutdown,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upgrade<C, St>(
|
||||
self,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
response_timeout_duration: Duration,
|
||||
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||
shutdown: TaskClient,
|
||||
) -> GatewayClient<C, St> {
|
||||
// invariants that can't be broken
|
||||
// (unless somebody decided to expose some field that wasn't meant to be exposed)
|
||||
assert!(self.authenticated);
|
||||
assert!(self.connection.is_available());
|
||||
assert!(self.shared_key.is_some());
|
||||
|
||||
GatewayClient {
|
||||
authenticated: self.authenticated,
|
||||
disabled_credentials_mode: self.disabled_credentials_mode,
|
||||
bandwidth_remaining: self.bandwidth_remaining,
|
||||
gateway_address: self.gateway_address,
|
||||
gateway_identity: self.gateway_identity,
|
||||
local_identity: self.local_identity,
|
||||
shared_key: self.shared_key,
|
||||
connection: self.connection,
|
||||
packet_router: PacketRouter::new(ack_sender, mixnet_message_sender, shutdown.clone()),
|
||||
response_timeout_duration,
|
||||
bandwidth_controller,
|
||||
should_reconnect_on_failure: self.should_reconnect_on_failure,
|
||||
reconnection_attempts: self.reconnection_attempts,
|
||||
reconnection_backoff: self.reconnection_backoff,
|
||||
shutdown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
futures = { workspace = true }
|
||||
futures = "0.3"
|
||||
log = { workspace = true }
|
||||
tokio = { version = "1.24.1", features = ["time", "net", "rt"] }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
|
||||
@@ -13,7 +13,6 @@ colored = "2.0"
|
||||
|
||||
nym-coconut-dkg-common = { path = "../../cosmwasm-smart-contracts/coconut-dkg" }
|
||||
nym-contracts-common = { path = "../../cosmwasm-smart-contracts/contracts-common" }
|
||||
nym-ephemera-common = { path = "../../cosmwasm-smart-contracts/ephemera" }
|
||||
nym-mixnet-contract-common = { path = "../../cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-vesting-contract-common = { path = "../../cosmwasm-smart-contracts/vesting-contract" }
|
||||
nym-coconut-bandwidth-contract-common = { path = "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
|
||||
@@ -21,50 +20,43 @@ nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig
|
||||
nym-name-service-common = { path = "../../cosmwasm-smart-contracts/name-service" }
|
||||
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
|
||||
nym-service-provider-directory-common = { path = "../../cosmwasm-smart-contracts/service-provider-directory" }
|
||||
nym-vesting-contract = { path = "../../../contracts/vesting" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
thiserror = { workspace = true }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
thiserror = "1"
|
||||
log = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
tokio = { workspace = true, features = ["sync", "time"] }
|
||||
futures = { workspace = true }
|
||||
openssl = { version = "^0.10.55", features = ["vendored"], optional = true }
|
||||
url = { version = "2.2", features = ["serde"] }
|
||||
tokio = { version = "1.24.1", features = ["sync", "time"] }
|
||||
futures = "0.3"
|
||||
openssl = { version = "0.10", features = ["vendored"], optional = true }
|
||||
|
||||
nym-coconut-interface = { path = "../../coconut-interface" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
nym-api-requests = { path = "../../../nym-api/nym-api-requests" }
|
||||
|
||||
async-trait = { workspace = true }
|
||||
bip39 = { workspace = true, features = ["rand"] }
|
||||
nym-config = { path = "../../config" }
|
||||
cosmrs = { workspace = true, features = ["bip32", "cosmwasm"] }
|
||||
# required for nyxd-client
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
# perhaps after https://github.com/cosmos/cosmos-rust/pull/97 is resolved (and tendermint-rs is updated)
|
||||
async-trait = { workspace = true, optional = true }
|
||||
bip39 = { workspace = true, features = ["rand"], optional = true }
|
||||
nym-config = { path = "../../config", optional = true }
|
||||
cosmrs = { workspace = true, features = ["rpc", "bip32", "cosmwasm"], optional = true }
|
||||
# note that this has the same version as used by cosmrs
|
||||
|
||||
# import it just for the `Client` trait
|
||||
tendermint-rpc = { workspace = true }
|
||||
|
||||
eyre = { version = "0.6" }
|
||||
cw-utils = { workspace = true }
|
||||
cw2 = { workspace = true }
|
||||
cw3 = { workspace = true }
|
||||
cw4 = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
prost = { version = "0.11", default-features = false }
|
||||
flate2 = { version = "1.0.20" }
|
||||
sha2 = { version = "0.9.5" }
|
||||
itertools = { version = "0.10" }
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
cosmwasm-std = { workspace = true }
|
||||
|
||||
# required for polling for broadcast result
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
eyre = { version = "0.6", optional = true }
|
||||
cw3 = { workspace = true, optional = true }
|
||||
cw4 = { workspace = true, optional = true }
|
||||
prost = { version = "0.10", default-features = false, optional = true }
|
||||
flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
zeroize = { version = "1.5.7", optional = true, features = ["zeroize_derive"] }
|
||||
cosmwasm-std = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bip39 = { workspace = true }
|
||||
cosmrs = { workspace = true, features = ["bip32"] }
|
||||
cosmrs = { workspace = true, features = ["rpc", "bip32"] }
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
[[example]]
|
||||
@@ -72,18 +64,36 @@ name = "offline_signing"
|
||||
# it should only really require the "signing" feature,
|
||||
# but that would require another round of refactoring to make it possible
|
||||
# (traits would need to be moved around and refactored themselves)
|
||||
required-features = ["http-client"]
|
||||
required-features = ["nyxd-client"]
|
||||
|
||||
[[example]]
|
||||
name = "query_service_provider_directory"
|
||||
required-features = ["http-client"]
|
||||
required-features = ["nyxd-client"]
|
||||
|
||||
[[example]]
|
||||
name = "query_name_service"
|
||||
required-features = ["http-client"]
|
||||
required-features = ["nyxd-client"]
|
||||
|
||||
[features]
|
||||
default = ["http-client"]
|
||||
http-client = ["cosmrs/rpc", "openssl"]
|
||||
nyxd-client = [
|
||||
"async-trait",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"flate2",
|
||||
"itertools",
|
||||
"openssl",
|
||||
"prost",
|
||||
"sha2",
|
||||
"signing"
|
||||
]
|
||||
signing = [
|
||||
"bip39",
|
||||
"cosmrs",
|
||||
"eyre",
|
||||
"nym-config",
|
||||
"zeroize"
|
||||
]
|
||||
generate-ts = []
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmrs::bank::MsgSend;
|
||||
use cosmrs::rpc::HttpClient;
|
||||
use cosmrs::rpc::{self, HttpClient};
|
||||
use cosmrs::tx::Msg;
|
||||
use cosmrs::{tx, AccountId, Coin, Denom};
|
||||
use nym_validator_client::nyxd::CosmWasmClient;
|
||||
@@ -23,7 +23,7 @@ async fn main() {
|
||||
let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone();
|
||||
|
||||
// local 'client' ONLY signing messages
|
||||
let tx_signer = signer;
|
||||
let tx_signer = TxSigner::new(signer);
|
||||
|
||||
// possibly remote client that doesn't do ANY signing
|
||||
// (only broadcasts + queries for sequence numbers)
|
||||
@@ -54,7 +54,7 @@ async fn main() {
|
||||
denom,
|
||||
amount: 2500u32.into(),
|
||||
},
|
||||
100000u32,
|
||||
100000,
|
||||
);
|
||||
|
||||
let tx_raw = tx_signer
|
||||
@@ -70,7 +70,7 @@ async fn main() {
|
||||
.unwrap();
|
||||
|
||||
// broadcast the tx
|
||||
let res = tendermint_rpc::client::Client::broadcast_tx_commit(&broadcaster, tx_bytes)
|
||||
let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ use std::str::FromStr;
|
||||
use cosmrs::AccountId;
|
||||
use nym_name_service_common::Address;
|
||||
use nym_network_defaults::{setup_env, NymNetworkDetails};
|
||||
use nym_validator_client::nyxd::contract_traits::{
|
||||
NameServiceQueryClient, PagedNameServiceQueryClient,
|
||||
};
|
||||
use nym_validator_client::nyxd::traits::NameServiceQueryClient;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -28,7 +26,7 @@ async fn main() {
|
||||
let names_by_owner = client.nyxd.get_names_by_owner(owner).await.unwrap();
|
||||
println!("names (by owner): {names_by_owner:#?}");
|
||||
|
||||
let nym_address = Address::new("client_id.client_key@gateway_id").unwrap();
|
||||
let nym_address = Address::new("client_id.client_key@gateway_id");
|
||||
let names_by_address = client.nyxd.get_names_by_address(nym_address).await.unwrap();
|
||||
println!("names (by address): {names_by_address:#?}");
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ use std::str::FromStr;
|
||||
use cosmrs::AccountId;
|
||||
use nym_network_defaults::{setup_env, NymNetworkDetails};
|
||||
use nym_service_provider_directory_common::NymAddress;
|
||||
use nym_validator_client::nyxd::contract_traits::{
|
||||
PagedSpDirectoryQueryClient, SpDirectoryQueryClient,
|
||||
};
|
||||
use nym_validator_client::nyxd::traits::SpDirectoryQueryClient;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
@@ -1,44 +1,61 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::{self, NyxdClient};
|
||||
use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
|
||||
use crate::signing::signer::{NoSigner, OfflineSigner};
|
||||
use crate::{
|
||||
nym_api, DirectSigningReqwestRpcValidatorClient, QueryReqwestRpcValidatorClient,
|
||||
ReqwestRpcClient, ValidatorClientError,
|
||||
};
|
||||
use crate::{nym_api, ValidatorClientError};
|
||||
use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::MixNodeBondAnnotated;
|
||||
use nym_api_requests::models::{
|
||||
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
|
||||
RewardEstimationResponse, StakeSaturationResponse,
|
||||
};
|
||||
use nym_network_defaults::NymNetworkDetails;
|
||||
use url::Url;
|
||||
|
||||
use nym_coconut_dkg_common::types::NodeIndex;
|
||||
use nym_coconut_interface::VerificationKey;
|
||||
pub use nym_mixnet_contract_common::{
|
||||
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, MixId,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
// re-export the type to not break existing imports
|
||||
pub use crate::coconut::CoconutApiClient;
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
use crate::{DirectSigningHttpRpcValidatorClient, HttpRpcClient, QueryHttpRpcValidatorClient};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use crate::nyxd::traits::{DkgQueryClient, MixnetQueryClient};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use crate::nyxd::{self, CosmWasmClient, NyxdClient, QueryNyxdClient, SigningNyxdClient};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use nym_api_requests::models::MixNodeBondAnnotated;
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use nym_coconut_dkg_common::{types::EpochId, verification_key::ContractVKShare};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use nym_coconut_interface::Base58;
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use nym_mixnet_contract_common::{
|
||||
families::{Family, FamilyHead},
|
||||
mixnode::MixNodeBond,
|
||||
pending_events::{PendingEpochEvent, PendingIntervalEvent},
|
||||
Delegation, RewardedSetNodeStatus, UnbondedMixnode,
|
||||
};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use nym_network_defaults::NymNetworkDetails;
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use std::str::FromStr;
|
||||
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
#[must_use]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
api_url: Url,
|
||||
nyxd_url: Url,
|
||||
|
||||
// TODO: until refactored, this is a dead field under some features
|
||||
nyxd_config: nyxd::Config,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
gateway_page_limit: Option<u32>,
|
||||
mixnode_delegations_page_limit: Option<u32>,
|
||||
rewarded_set_page_limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl Config {
|
||||
pub fn try_from_nym_network_details(
|
||||
details: &NymNetworkDetails,
|
||||
@@ -61,6 +78,10 @@ impl Config {
|
||||
.parse()
|
||||
.map_err(ValidatorClientError::MalformedUrlProvided)?,
|
||||
nyxd_config: nyxd::Config::try_from_nym_network_details(details)?,
|
||||
mixnode_page_limit: None,
|
||||
gateway_page_limit: None,
|
||||
mixnode_delegations_page_limit: None,
|
||||
rewarded_set_page_limit: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,57 +98,88 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_simulated_gas_multiplier(mut self, gas_multiplier: f32) -> Self {
|
||||
self.nyxd_config.simulated_gas_multiplier = gas_multiplier;
|
||||
pub fn with_mixnode_page_limit(mut self, limit: Option<u32>) -> Config {
|
||||
self.mixnode_page_limit = limit;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gateway_page_limit(mut self, limit: Option<u32>) -> Config {
|
||||
self.gateway_page_limit = limit;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mixnode_delegations_page_limit(mut self, limit: Option<u32>) -> Config {
|
||||
self.mixnode_delegations_page_limit = limit;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_rewarded_set_page_limit(mut self, limit: Option<u32>) -> Config {
|
||||
self.rewarded_set_page_limit = limit;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Client<C, S = NoSigner> {
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
pub struct Client<C> {
|
||||
mixnode_page_limit: Option<u32>,
|
||||
gateway_page_limit: Option<u32>,
|
||||
mixnode_delegations_page_limit: Option<u32>,
|
||||
rewarded_set_page_limit: Option<u32>,
|
||||
|
||||
// ideally they would have been read-only, but unfortunately rust doesn't have such features
|
||||
pub nym_api: nym_api::Client,
|
||||
pub nyxd: NyxdClient<C, S>,
|
||||
pub nyxd: NyxdClient<C>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
impl Client<HttpRpcClient, DirectSecp256k1HdWallet> {
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl Client<SigningNyxdClient<DirectSecp256k1HdWallet>> {
|
||||
pub fn new_signing(
|
||||
config: Config,
|
||||
mnemonic: bip39::Mnemonic,
|
||||
) -> Result<DirectSigningHttpRpcValidatorClient, ValidatorClientError> {
|
||||
let rpc_client = HttpRpcClient::new(config.nyxd_url.as_str())?;
|
||||
let prefix = &config.nyxd_config.chain_details.bech32_account_prefix;
|
||||
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic);
|
||||
) -> Result<Client<SigningNyxdClient<DirectSecp256k1HdWallet>>, ValidatorClientError> {
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let nyxd_client = NyxdClient::connect_with_mnemonic(
|
||||
config.nyxd_config.clone(),
|
||||
config.nyxd_url.as_str(),
|
||||
mnemonic,
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok(Self::new_signing_with_rpc_client(
|
||||
config, rpc_client, wallet,
|
||||
))
|
||||
Ok(Client {
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
||||
nym_api: nym_api_client,
|
||||
nyxd: nyxd_client,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn change_nyxd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||
self.nyxd.change_endpoint(new_endpoint.as_ref())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<ReqwestRpcClient, DirectSecp256k1HdWallet> {
|
||||
pub fn new_reqwest_signing(
|
||||
config: Config,
|
||||
mnemonic: bip39::Mnemonic,
|
||||
) -> DirectSigningReqwestRpcValidatorClient {
|
||||
let rpc_client = ReqwestRpcClient::new(config.nyxd_url.clone());
|
||||
let prefix = &config.nyxd_config.chain_details.bech32_account_prefix;
|
||||
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic);
|
||||
|
||||
Self::new_signing_with_rpc_client(config, rpc_client, wallet)
|
||||
pub fn set_nyxd_simulated_gas_multiplier(&mut self, multiplier: f32) {
|
||||
self.nyxd.set_simulated_gas_multiplier(multiplier)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
impl Client<HttpRpcClient> {
|
||||
pub fn new_query(config: Config) -> Result<QueryHttpRpcValidatorClient, ValidatorClientError> {
|
||||
let rpc_client = HttpRpcClient::new(config.nyxd_url.as_str())?;
|
||||
Ok(Self::new_with_rpc_client(config, rpc_client))
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl Client<QueryNyxdClient> {
|
||||
pub fn new_query(config: Config) -> Result<Client<QueryNyxdClient>, ValidatorClientError> {
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let nyxd_client =
|
||||
NyxdClient::connect(config.nyxd_config.clone(), config.nyxd_url.as_str())?;
|
||||
|
||||
Ok(Client {
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
||||
nym_api: nym_api_client,
|
||||
nyxd: nyxd_client,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn change_nyxd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||
@@ -136,40 +188,392 @@ impl Client<HttpRpcClient> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<ReqwestRpcClient> {
|
||||
pub fn new_reqwest_query(config: Config) -> QueryReqwestRpcValidatorClient {
|
||||
let rpc_client = ReqwestRpcClient::new(config.nyxd_url.clone());
|
||||
Self::new_with_rpc_client(config, rpc_client)
|
||||
}
|
||||
}
|
||||
|
||||
// nyxd wrappers
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl<C> Client<C> {
|
||||
pub fn new_with_rpc_client(config: Config, rpc_client: C) -> Self {
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
// use case: somebody initialised client without a contract in order to upload and initialise one
|
||||
// and now they want to actually use it without making new client
|
||||
|
||||
Client {
|
||||
nym_api: nym_api_client,
|
||||
nyxd: NyxdClient::new(config.nyxd_config, rpc_client),
|
||||
}
|
||||
pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) {
|
||||
self.nyxd
|
||||
.set_mixnet_contract_address(mixnet_contract_address)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, S> Client<C, S> {
|
||||
pub fn new_signing_with_rpc_client(config: Config, rpc_client: C, signer: S) -> Self
|
||||
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
|
||||
self.nyxd.mixnet_contract_address().clone()
|
||||
}
|
||||
|
||||
pub async fn get_all_node_families(&self) -> Result<Vec<Family>, ValidatorClientError>
|
||||
where
|
||||
S: OfflineSigner,
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let mut families = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
Client {
|
||||
nym_api: nym_api_client,
|
||||
nyxd: NyxdClient::new_signing(config.nyxd_config, rpc_client, signer),
|
||||
loop {
|
||||
let paged_response = self
|
||||
.nyxd
|
||||
.get_all_node_families_paged(start_after.take(), None)
|
||||
.await?;
|
||||
families.extend(paged_response.families);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(families)
|
||||
}
|
||||
|
||||
pub async fn get_all_family_members(
|
||||
&self,
|
||||
) -> Result<Vec<(IdentityKey, FamilyHead)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut members = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let paged_response = self
|
||||
.nyxd
|
||||
.get_all_family_members_paged(start_after.take(), None)
|
||||
.await?;
|
||||
members.extend(paged_response.members);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(members)
|
||||
}
|
||||
|
||||
// basically handles paging for us
|
||||
pub async fn get_all_nyxd_rewarded_set_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut identities = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_rewarded_set_paged(start_after.take(), self.rewarded_set_page_limit)
|
||||
.await?;
|
||||
identities.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(identities)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut mixnodes = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_mixnode_bonds_paged(self.mixnode_page_limit, start_after.take())
|
||||
.await?;
|
||||
mixnodes.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mixnodes)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut mixnodes = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_mixnodes_detailed_paged(self.mixnode_page_limit, start_after.take())
|
||||
.await?;
|
||||
mixnodes.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mixnodes)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_unbonded_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut mixnodes = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_unbonded_paged(self.mixnode_page_limit, start_after.take())
|
||||
.await?;
|
||||
mixnodes.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mixnodes)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_unbonded_mixnodes_by_owner(
|
||||
&self,
|
||||
owner: &cosmrs::AccountId,
|
||||
) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut mixnodes = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_unbonded_by_owner_paged(owner, self.mixnode_page_limit, start_after.take())
|
||||
.await?;
|
||||
mixnodes.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mixnodes)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_unbonded_mixnodes_by_identity(
|
||||
&self,
|
||||
identity_key: String,
|
||||
) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut mixnodes = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_unbonded_by_identity_paged(
|
||||
identity_key.clone(),
|
||||
self.mixnode_page_limit,
|
||||
start_after.take(),
|
||||
)
|
||||
.await?;
|
||||
mixnodes.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mixnodes)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut gateways = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_gateways_paged(start_after.take(), self.gateway_page_limit)
|
||||
.await?;
|
||||
gateways.append(&mut paged_response.nodes);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(gateways)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_single_mixnode_delegations(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut delegations = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_mixnode_delegations_paged(
|
||||
mix_id,
|
||||
start_after.take(),
|
||||
self.mixnode_delegations_page_limit,
|
||||
)
|
||||
.await?;
|
||||
delegations.append(&mut paged_response.delegations);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(delegations)
|
||||
}
|
||||
|
||||
pub async fn get_all_delegator_delegations(
|
||||
&self,
|
||||
delegation_owner: &cosmrs::AccountId,
|
||||
) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut delegations = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_delegator_delegations_paged(
|
||||
delegation_owner.to_string(),
|
||||
start_after.take(),
|
||||
self.mixnode_delegations_page_limit,
|
||||
)
|
||||
.await?;
|
||||
delegations.append(&mut paged_response.delegations);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(delegations)
|
||||
}
|
||||
|
||||
pub async fn get_all_network_delegations(&self) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut delegations = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_all_network_delegations_paged(
|
||||
start_after.take(),
|
||||
self.mixnode_delegations_page_limit,
|
||||
)
|
||||
.await?;
|
||||
delegations.append(&mut paged_response.delegations);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(delegations)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_pending_epoch_events(
|
||||
&self,
|
||||
) -> Result<Vec<PendingEpochEvent>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut events = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_pending_epoch_events_paged(start_after.take(), self.rewarded_set_page_limit)
|
||||
.await?;
|
||||
events.append(&mut paged_response.events);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
pub async fn get_all_nyxd_pending_interval_events(
|
||||
&self,
|
||||
) -> Result<Vec<PendingIntervalEvent>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
let mut events = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_pending_interval_events_paged(start_after.take(), self.rewarded_set_page_limit)
|
||||
.await?;
|
||||
events.append(&mut paged_response.events);
|
||||
|
||||
if let Some(start_after_res) = paged_response.start_next_after {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
|
||||
// validator-api wrappers
|
||||
impl<C, S> Client<C, S> {
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl<C> Client<C> {
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api.change_url(new_endpoint)
|
||||
}
|
||||
@@ -226,42 +630,87 @@ impl<C, S> Client<C, S> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoconutApiClient {
|
||||
pub api_client: NymApiClient,
|
||||
pub verification_key: VerificationKey,
|
||||
pub node_id: NodeIndex,
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
pub cosmos_address: cosmrs::AccountId,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl CoconutApiClient {
|
||||
pub async fn all_coconut_api_clients<C>(
|
||||
client: &C,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<Self>, ValidatorClientError>
|
||||
where
|
||||
C: DkgQueryClient + Sync + Send,
|
||||
{
|
||||
Ok(client
|
||||
.get_all_verification_key_shares(epoch_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(Self::try_from)
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn try_from(share: ContractVKShare) -> Option<Self> {
|
||||
if share.verified {
|
||||
if let Ok(url_address) = Url::parse(&share.announce_address) {
|
||||
if let Ok(verification_key) = VerificationKey::try_from_bs58(&share.share) {
|
||||
if let Ok(cosmos_address) = cosmrs::AccountId::from_str(share.owner.as_str()) {
|
||||
return Some(CoconutApiClient {
|
||||
api_client: NymApiClient::new(url_address),
|
||||
verification_key,
|
||||
node_id: share.node_index,
|
||||
cosmos_address,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NymApiClient {
|
||||
pub nym_api: nym_api::Client,
|
||||
pub nym_api_client: nym_api::Client,
|
||||
// TODO: perhaps if we really need it at some (currently I don't see any reasons for it)
|
||||
// we could re-implement the communication with the REST API on port 1317
|
||||
}
|
||||
|
||||
impl NymApiClient {
|
||||
pub fn new(api_url: Url) -> Self {
|
||||
let nym_api = nym_api::Client::new(api_url);
|
||||
let nym_api_client = nym_api::Client::new(api_url);
|
||||
|
||||
NymApiClient { nym_api }
|
||||
NymApiClient { nym_api_client }
|
||||
}
|
||||
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api.change_url(new_endpoint);
|
||||
self.nym_api_client.change_url(new_endpoint);
|
||||
}
|
||||
|
||||
pub async fn get_cached_active_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_active_mixnodes().await?)
|
||||
Ok(self.nym_api_client.get_active_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_rewarded_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_rewarded_mixnodes().await?)
|
||||
Ok(self.nym_api_client.get_rewarded_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_mixnodes().await?)
|
||||
Ok(self.nym_api_client.get_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_gateways().await?)
|
||||
Ok(self.nym_api_client.get_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn get_gateway_core_status_count(
|
||||
@@ -270,7 +719,7 @@ impl NymApiClient {
|
||||
since: Option<i64>,
|
||||
) -> Result<GatewayCoreStatusResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.nym_api
|
||||
.nym_api_client
|
||||
.get_gateway_core_status_count(identity, since)
|
||||
.await?)
|
||||
}
|
||||
@@ -281,7 +730,7 @@ impl NymApiClient {
|
||||
since: Option<i64>,
|
||||
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.nym_api
|
||||
.nym_api_client
|
||||
.get_mixnode_core_status_count(mix_id, since)
|
||||
.await?)
|
||||
}
|
||||
@@ -290,28 +739,34 @@ impl NymApiClient {
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_mixnode_status(mix_id).await?)
|
||||
Ok(self.nym_api_client.get_mixnode_status(mix_id).await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_reward_estimation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<RewardEstimationResponse, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?)
|
||||
Ok(self
|
||||
.nym_api_client
|
||||
.get_mixnode_reward_estimation(mix_id)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_stake_saturation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<StakeSaturationResponse, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?)
|
||||
Ok(self
|
||||
.nym_api_client
|
||||
.get_mixnode_stake_saturation(mix_id)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
|
||||
Ok(self.nym_api.blind_sign(request_body).await?)
|
||||
Ok(self.nym_api_client.blind_sign(request_body).await?)
|
||||
}
|
||||
|
||||
pub async fn verify_bandwidth_credential(
|
||||
@@ -319,7 +774,7 @@ impl NymApiClient {
|
||||
request_body: &VerifyCredentialBody,
|
||||
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.nym_api
|
||||
.nym_api_client
|
||||
.verify_bandwidth_credential(request_body)
|
||||
.await?)
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::{DkgQueryClient, PagedDkgQueryClient};
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::NymApiClient;
|
||||
use nym_coconut_dkg_common::types::{EpochId, NodeIndex};
|
||||
use nym_coconut_dkg_common::verification_key::ContractVKShare;
|
||||
use nym_coconut_interface::{Base58, CoconutError, VerificationKey};
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
// TODO: it really doesn't feel like this should live in this crate.
|
||||
#[derive(Clone)]
|
||||
pub struct CoconutApiClient {
|
||||
pub api_client: NymApiClient,
|
||||
pub verification_key: VerificationKey,
|
||||
pub node_id: NodeIndex,
|
||||
pub cosmos_address: cosmrs::AccountId,
|
||||
}
|
||||
|
||||
// TODO: this should be using the coconut error
|
||||
// (which is in different crate; perhaps this client should be moved there?)
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CoconutApiError {
|
||||
// TODO: ask @BN whether this is a correct error message
|
||||
#[error("the provided key share hasn't been verified")]
|
||||
UnverifiedShare,
|
||||
|
||||
#[error("failed to query the contract: {source}")]
|
||||
ContractQueryFailure {
|
||||
#[from]
|
||||
source: NyxdError,
|
||||
},
|
||||
|
||||
#[error("the provided announce address is malformed: {source}")]
|
||||
MalformedAnnounceAddress {
|
||||
#[from]
|
||||
source: url::ParseError,
|
||||
},
|
||||
|
||||
#[error("the provided verification key is malformed: {source}")]
|
||||
MalformedVerificationKey {
|
||||
#[from]
|
||||
source: CoconutError,
|
||||
},
|
||||
|
||||
#[error("the provided account address is malformed: {source}")]
|
||||
MalformedAccountAddress {
|
||||
#[from]
|
||||
source: cosmrs::ErrorReport,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<ContractVKShare> for CoconutApiClient {
|
||||
type Error = CoconutApiError;
|
||||
|
||||
fn try_from(share: ContractVKShare) -> Result<Self, Self::Error> {
|
||||
if !share.verified {
|
||||
return Err(CoconutApiError::UnverifiedShare);
|
||||
}
|
||||
|
||||
let url_address = Url::parse(&share.announce_address)?;
|
||||
|
||||
Ok(CoconutApiClient {
|
||||
api_client: NymApiClient::new(url_address),
|
||||
verification_key: VerificationKey::try_from_bs58(&share.share)?,
|
||||
node_id: share.node_index,
|
||||
cosmos_address: share.owner.as_str().parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn all_coconut_api_clients<C>(
|
||||
client: &C,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<CoconutApiClient>, CoconutApiError>
|
||||
where
|
||||
C: DkgQueryClient + Sync + Send,
|
||||
{
|
||||
// TODO: this will error out if there's an invalid share out there. is that what we want?
|
||||
client
|
||||
.get_all_verification_key_shares(epoch_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
|
||||
// ... if not, let's switch to the below:
|
||||
// client
|
||||
// .get_all_verification_key_shares(epoch_id)
|
||||
// .await?
|
||||
// .into_iter()
|
||||
// .filter_map(TryInto::try_into)
|
||||
// .collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::nyxd::contract_traits::MixnetQueryClient;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::Config as ClientConfig;
|
||||
use crate::{NymApiClient, QueryHttpRpcNyxdClient, ValidatorClientError};
|
||||
use crate::nyxd::{Config as ClientConfig, NyxdClient, QueryNyxdClient};
|
||||
use crate::{NymApiClient, ValidatorClientError};
|
||||
|
||||
use crate::nyxd::traits::MixnetQueryClient;
|
||||
use colored::Colorize;
|
||||
use core::fmt;
|
||||
use itertools::Itertools;
|
||||
@@ -52,7 +53,7 @@ pub async fn test_nyxd_url_connection(
|
||||
let config = ClientConfig::try_from_nym_network_details(&network)
|
||||
.expect("failed to create valid nyxd client config");
|
||||
|
||||
let mut nyxd_client = QueryHttpRpcNyxdClient::connect(config, nyxd_url.as_str())?;
|
||||
let mut nyxd_client = NyxdClient::<QueryNyxdClient>::connect(config, nyxd_url.as_str())?;
|
||||
// possibly redundant, but lets just leave it here
|
||||
nyxd_client.set_mixnet_contract_address(address);
|
||||
match test_nyxd_connection(network, &nyxd_url, &nyxd_client).await {
|
||||
@@ -74,7 +75,7 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
|
||||
let config = ClientConfig::try_from_nym_network_details(&network)
|
||||
.expect("failed to create valid nyxd client config");
|
||||
|
||||
if let Ok(mut client) = QueryHttpRpcNyxdClient::connect(config, url.as_str()) {
|
||||
if let Ok(mut client) = NyxdClient::<QueryNyxdClient>::connect(config, url.as_str()) {
|
||||
// possibly redundant, but lets just leave it here
|
||||
client.set_mixnet_contract_address(address);
|
||||
Some(ClientForConnectionTest::Nyxd(
|
||||
@@ -111,7 +112,7 @@ fn extract_and_collect_results_into_map(
|
||||
async fn test_nyxd_connection(
|
||||
network: NymNetworkDetails,
|
||||
url: &Url,
|
||||
client: &QueryHttpRpcNyxdClient,
|
||||
client: &NyxdClient<QueryNyxdClient>,
|
||||
) -> ConnectionResult {
|
||||
let result = match timeout(
|
||||
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
|
||||
@@ -119,7 +120,7 @@ async fn test_nyxd_connection(
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(Err(NyxdError::TendermintErrorRpc(e))) => {
|
||||
Ok(Err(NyxdError::TendermintError(e))) => {
|
||||
// If we get a tendermint-rpc error, we classify the node as not contactable
|
||||
log::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
|
||||
false
|
||||
@@ -185,7 +186,7 @@ async fn test_nym_api_connection(
|
||||
}
|
||||
|
||||
enum ClientForConnectionTest {
|
||||
Nyxd(NymNetworkDetails, Url, Box<QueryHttpRpcNyxdClient>),
|
||||
Nyxd(NymNetworkDetails, Url, Box<NyxdClient<QueryNyxdClient>>),
|
||||
Api(NymNetworkDetails, Url, NymApiClient),
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nym_api;
|
||||
pub use tendermint_rpc::error::Error as TendermintRpcError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -13,12 +12,10 @@ pub enum ValidatorClientError {
|
||||
source: nym_api::error::NymAPIError,
|
||||
},
|
||||
|
||||
#[error("Tendermint RPC request failure: {0}")]
|
||||
TendermintErrorRpc(#[from] TendermintRpcError),
|
||||
|
||||
#[error("One of the provided URLs was malformed - {0}")]
|
||||
MalformedUrlProvided(#[from] url::ParseError),
|
||||
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
#[error("nyxd request failed - {0}")]
|
||||
NyxdError(#[from] crate::nyxd::error::NyxdError),
|
||||
|
||||
|
||||
@@ -1,44 +1,20 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod client;
|
||||
pub mod coconut;
|
||||
#[cfg(feature = "http-client")]
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
pub mod connection_tester;
|
||||
pub mod error;
|
||||
pub mod nym_api;
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
pub mod nyxd;
|
||||
pub mod rpc;
|
||||
|
||||
#[cfg(feature = "signing")]
|
||||
pub mod signing;
|
||||
|
||||
pub use crate::error::ValidatorClientError;
|
||||
pub use crate::rpc::reqwest::ReqwestRpcClient;
|
||||
pub use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
|
||||
pub use client::NymApiClient;
|
||||
pub use client::{Client, CoconutApiClient, Config};
|
||||
pub use nym_api_requests::*;
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
pub use cosmrs::rpc::HttpClient as HttpRpcClient;
|
||||
|
||||
// some type aliasing
|
||||
|
||||
pub type ValidatorClient<C> = Client<C>;
|
||||
pub type SigningValidatorClient<C, S> = Client<C, S>;
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
pub type QueryHttpRpcValidatorClient = Client<HttpRpcClient>;
|
||||
#[cfg(feature = "http-client")]
|
||||
pub type QueryHttpRpcNyxdClient = nyxd::NyxdClient<HttpRpcClient>;
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
pub type DirectSigningHttpRpcValidatorClient = Client<HttpRpcClient, DirectSecp256k1HdWallet>;
|
||||
#[cfg(feature = "http-client")]
|
||||
pub type DirectSigningHttpRpcNyxdClient = nyxd::NyxdClient<HttpRpcClient, DirectSecp256k1HdWallet>;
|
||||
|
||||
pub type QueryReqwestRpcValidatorClient = Client<ReqwestRpcClient>;
|
||||
pub type QueryReqwestRpcNyxdClient = nyxd::NyxdClient<ReqwestRpcClient>;
|
||||
|
||||
pub type DirectSigningReqwestRpcValidatorClient = Client<ReqwestRpcClient, DirectSecp256k1HdWallet>;
|
||||
pub type DirectSigningReqwestRpcNyxdClient =
|
||||
nyxd::NyxdClient<ReqwestRpcClient, DirectSecp256k1HdWallet>;
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
pub use client::{Client, CoconutApiClient, Config};
|
||||
|
||||
@@ -7,11 +7,11 @@ use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
|
||||
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
|
||||
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
|
||||
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RequestError, RewardEstimationResponse,
|
||||
StakeSaturationResponse, UptimeResponse,
|
||||
ComputeRewardEstParam, GatewayCoreStatusResponse, GatewayStatusReportResponse,
|
||||
GatewayUptimeHistoryResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
|
||||
MixnodeCoreStatusResponse, MixnodeStatusReportResponse, MixnodeStatusResponse,
|
||||
MixnodeUptimeHistoryResponse, RequestError, RewardEstimationResponse, StakeSaturationResponse,
|
||||
UptimeResponse,
|
||||
};
|
||||
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
|
||||
@@ -148,19 +148,6 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
routes::GATEWAYS,
|
||||
routes::DETAILED,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes_detailed_unfiltered(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
|
||||
@@ -52,6 +52,7 @@ impl<'a> Div<GasPrice> for &'a Coin {
|
||||
} else {
|
||||
implicit_gas_limit.u128() as u64
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,32 +191,32 @@ mod tests {
|
||||
let amount = Coin::new(3938, "unym");
|
||||
let gas_price = "0.025unym".parse().unwrap();
|
||||
let res = amount / gas_price;
|
||||
assert_eq!(157520, res);
|
||||
assert_eq!(157520, res.value());
|
||||
|
||||
let amount = Coin::new(1234567890, "unym");
|
||||
let gas_price = "0.025unym".parse().unwrap();
|
||||
let res = amount / gas_price;
|
||||
assert_eq!(49382715600, res);
|
||||
assert_eq!(49382715600, res.value());
|
||||
|
||||
let amount = Coin::new(1, "unym");
|
||||
let gas_price = "0.025unym".parse().unwrap();
|
||||
let res = amount / gas_price;
|
||||
assert_eq!(40, res);
|
||||
assert_eq!(40, res.value());
|
||||
|
||||
let amount = Coin::new(150_000_000, "unym");
|
||||
let gas_price = "0.001234unym".parse().unwrap();
|
||||
let res = amount / gas_price;
|
||||
assert_eq!(121555915721, res);
|
||||
assert_eq!(121555915721, res.value());
|
||||
|
||||
let amount = Coin::new(150_000_000, "unym");
|
||||
let gas_price = "1unym".parse().unwrap();
|
||||
let res = amount / gas_price;
|
||||
assert_eq!(150_000_000, res);
|
||||
assert_eq!(150_000_000, res.value());
|
||||
|
||||
let amount = Coin::new(150_000_000, "unym");
|
||||
let gas_price = "1234.56unym".parse().unwrap();
|
||||
let res = amount / gas_price;
|
||||
assert_eq!(121500, res);
|
||||
assert_eq!(121500, res.value());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::collect_paged;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use nym_coconut_bandwidth_contract_common::msg::QueryMsg as CoconutBandwidthQueryMsg;
|
||||
use nym_coconut_bandwidth_contract_common::spend_credential::{
|
||||
PagedSpendCredentialResponse, SpendCredential, SpendCredentialResponse,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait CoconutBandwidthQueryClient {
|
||||
async fn query_coconut_bandwidth_contract<T>(
|
||||
&self,
|
||||
query: CoconutBandwidthQueryMsg,
|
||||
) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn get_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number: String,
|
||||
) -> Result<SpendCredentialResponse, NyxdError> {
|
||||
self.query_coconut_bandwidth_contract(CoconutBandwidthQueryMsg::GetSpentCredential {
|
||||
blinded_serial_number,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_all_spent_credential_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedSpendCredentialResponse, NyxdError> {
|
||||
self.query_coconut_bandwidth_contract(CoconutBandwidthQueryMsg::GetAllSpentCredentials {
|
||||
limit,
|
||||
start_after,
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedCoconutBandwidthQueryClient: CoconutBandwidthQueryClient {
|
||||
async fn get_all_spent_credentials(&self) -> Result<Vec<SpendCredential>, NyxdError> {
|
||||
collect_paged!(self, get_all_spent_credential_paged, spend_credentials)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedCoconutBandwidthQueryClient for T where T: CoconutBandwidthQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> CoconutBandwidthQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_coconut_bandwidth_contract<T>(
|
||||
&self,
|
||||
query: CoconutBandwidthQueryMsg,
|
||||
) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let coconut_bandwidth_contract_address = self
|
||||
.coconut_bandwidth_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("coconut bandwidth contract"))?;
|
||||
self.query_contract_smart(coconut_bandwidth_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: CoconutBandwidthQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: CoconutBandwidthQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
CoconutBandwidthQueryMsg::GetSpentCredential {
|
||||
blinded_serial_number,
|
||||
} => client.get_spent_credential(blinded_serial_number).ignore(),
|
||||
CoconutBandwidthQueryMsg::GetAllSpentCredentials { limit, start_after } => client
|
||||
.get_all_spent_credential_paged(start_after, limit)
|
||||
.ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
|
||||
use crate::signing::signer::OfflineSigner;
|
||||
use async_trait::async_trait;
|
||||
use nym_coconut_bandwidth_contract_common::spend_credential::SpendCredentialData;
|
||||
use nym_coconut_bandwidth_contract_common::{
|
||||
deposit::DepositData, msg::ExecuteMsg as CoconutBandwidthExecuteMsg,
|
||||
};
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait CoconutBandwidthSigningClient {
|
||||
async fn execute_coconut_bandwidth_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: CoconutBandwidthExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn deposit(
|
||||
&self,
|
||||
amount: Coin,
|
||||
info: String,
|
||||
verification_key: String,
|
||||
encryption_key: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = CoconutBandwidthExecuteMsg::DepositFunds {
|
||||
data: DepositData::new(info.to_string(), verification_key, encryption_key),
|
||||
};
|
||||
self.execute_coconut_bandwidth_contract(
|
||||
fee,
|
||||
req,
|
||||
"CoconutBandwidth::Deposit".to_string(),
|
||||
vec![amount],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn spend_credential(
|
||||
&self,
|
||||
funds: Coin,
|
||||
blinded_serial_number: String,
|
||||
gateway_cosmos_address: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = CoconutBandwidthExecuteMsg::SpendCredential {
|
||||
data: SpendCredentialData::new(
|
||||
funds.into(),
|
||||
blinded_serial_number,
|
||||
gateway_cosmos_address,
|
||||
),
|
||||
};
|
||||
self.execute_coconut_bandwidth_contract(
|
||||
fee,
|
||||
req,
|
||||
"CoconutBandwidth::SpendCredential".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn release_funds(
|
||||
&self,
|
||||
amount: Coin,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_coconut_bandwidth_contract(
|
||||
fee,
|
||||
CoconutBandwidthExecuteMsg::ReleaseFunds {
|
||||
funds: amount.into(),
|
||||
},
|
||||
"CoconutBandwidth::ReleaseFunds".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> CoconutBandwidthSigningClient for C
|
||||
where
|
||||
C: SigningCosmWasmClient + NymContractsProvider + Sync,
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
async fn execute_coconut_bandwidth_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: CoconutBandwidthExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let coconut_bandwidth_contract_address = self
|
||||
.coconut_bandwidth_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("coconut bandwidth contract"))?;
|
||||
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
|
||||
let signer_address = &self.signer_addresses()?[0];
|
||||
|
||||
self.execute(
|
||||
signer_address,
|
||||
coconut_bandwidth_contract_address,
|
||||
&msg,
|
||||
fee,
|
||||
memo,
|
||||
funds,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_execute_variants_are_covered<C: CoconutBandwidthSigningClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: CoconutBandwidthExecuteMsg,
|
||||
) {
|
||||
match msg {
|
||||
CoconutBandwidthExecuteMsg::DepositFunds { data } => client
|
||||
.deposit(
|
||||
mock_coin(),
|
||||
data.deposit_info().to_string(),
|
||||
data.identity_key().to_string(),
|
||||
data.encryption_key().to_string(),
|
||||
None,
|
||||
)
|
||||
.ignore(),
|
||||
CoconutBandwidthExecuteMsg::SpendCredential { data } => client
|
||||
.spend_credential(
|
||||
mock_coin(),
|
||||
data.blinded_serial_number().to_string(),
|
||||
data.gateway_cosmos_address().to_string(),
|
||||
None,
|
||||
)
|
||||
.ignore(),
|
||||
CoconutBandwidthExecuteMsg::ReleaseFunds { funds } => {
|
||||
client.release_funds(funds.into(), None).ignore()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::collect_paged;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use nym_coconut_dkg_common::dealer::{
|
||||
ContractDealing, DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse,
|
||||
};
|
||||
use nym_coconut_dkg_common::msg::QueryMsg as DkgQueryMsg;
|
||||
use nym_coconut_dkg_common::types::{DealerDetails, Epoch, EpochId, InitialReplacementData};
|
||||
use nym_coconut_dkg_common::verification_key::{ContractVKShare, PagedVKSharesResponse};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait DkgQueryClient {
|
||||
async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn get_current_epoch(&self) -> Result<Epoch, NyxdError> {
|
||||
let request = DkgQueryMsg::GetCurrentEpochState {};
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
async fn get_current_epoch_threshold(&self) -> Result<Option<u64>, NyxdError> {
|
||||
let request = DkgQueryMsg::GetCurrentEpochThreshold {};
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
|
||||
async fn get_initial_dealers(&self) -> Result<Option<InitialReplacementData>, NyxdError> {
|
||||
let request = DkgQueryMsg::GetInitialDealers {};
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
|
||||
async fn get_dealer_details(
|
||||
&self,
|
||||
address: &AccountId,
|
||||
) -> Result<DealerDetailsResponse, NyxdError> {
|
||||
let request = DkgQueryMsg::GetDealerDetails {
|
||||
dealer_address: address.to_string(),
|
||||
};
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
|
||||
async fn get_current_dealers_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedDealerResponse, NyxdError> {
|
||||
let request = DkgQueryMsg::GetCurrentDealers { start_after, limit };
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
|
||||
async fn get_past_dealers_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedDealerResponse, NyxdError> {
|
||||
let request = DkgQueryMsg::GetPastDealers { start_after, limit };
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
|
||||
async fn get_dealings_paged(
|
||||
&self,
|
||||
idx: u64,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedDealingsResponse, NyxdError> {
|
||||
let request = DkgQueryMsg::GetDealing {
|
||||
idx,
|
||||
limit,
|
||||
start_after,
|
||||
};
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
|
||||
async fn get_vk_shares_paged(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedVKSharesResponse, NyxdError> {
|
||||
let request = DkgQueryMsg::GetVerificationKeys {
|
||||
epoch_id,
|
||||
limit,
|
||||
start_after,
|
||||
};
|
||||
self.query_dkg_contract(request).await
|
||||
}
|
||||
}
|
||||
|
||||
// extension trait to the query client to deal with the paged queries
|
||||
// (it didn't feel appropriate to combine it with the existing trait
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedDkgQueryClient: DkgQueryClient {
|
||||
async fn get_all_current_dealers(&self) -> Result<Vec<DealerDetails>, NyxdError> {
|
||||
collect_paged!(self, get_current_dealers_paged, dealers)
|
||||
}
|
||||
|
||||
async fn get_all_past_dealers(&self) -> Result<Vec<DealerDetails>, NyxdError> {
|
||||
collect_paged!(self, get_past_dealers_paged, dealers)
|
||||
}
|
||||
|
||||
async fn get_all_epoch_dealings(&self, idx: u64) -> Result<Vec<ContractDealing>, NyxdError> {
|
||||
collect_paged!(self, get_dealings_paged, dealings, idx)
|
||||
}
|
||||
|
||||
async fn get_all_verification_key_shares(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<ContractVKShare>, NyxdError> {
|
||||
collect_paged!(self, get_vk_shares_paged, shares, epoch_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedDkgQueryClient for T where T: DkgQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> DkgQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let dkg_contract_address = &self
|
||||
.dkg_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("dkg contract"))?;
|
||||
self.query_contract_smart(dkg_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: DkgQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: DkgQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
DkgQueryMsg::GetCurrentEpochState {} => client.get_current_epoch().ignore(),
|
||||
DkgQueryMsg::GetCurrentEpochThreshold {} => {
|
||||
client.get_current_epoch_threshold().ignore()
|
||||
}
|
||||
DkgQueryMsg::GetInitialDealers {} => client.get_initial_dealers().ignore(),
|
||||
DkgQueryMsg::GetDealerDetails { dealer_address } => client
|
||||
.get_dealer_details(&dealer_address.parse().unwrap())
|
||||
.ignore(),
|
||||
DkgQueryMsg::GetCurrentDealers { limit, start_after } => client
|
||||
.get_current_dealers_paged(start_after, limit)
|
||||
.ignore(),
|
||||
DkgQueryMsg::GetPastDealers { limit, start_after } => {
|
||||
client.get_past_dealers_paged(start_after, limit).ignore()
|
||||
}
|
||||
DkgQueryMsg::GetDealing {
|
||||
idx,
|
||||
limit,
|
||||
start_after,
|
||||
} => client.get_dealings_paged(idx, start_after, limit).ignore(),
|
||||
DkgQueryMsg::GetVerificationKeys {
|
||||
epoch_id,
|
||||
limit,
|
||||
start_after,
|
||||
} => client
|
||||
.get_vk_shares_paged(epoch_id, start_after, limit)
|
||||
.ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
|
||||
use crate::signing::signer::OfflineSigner;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use cosmwasm_std::Addr;
|
||||
use nym_coconut_dkg_common::msg::ExecuteMsg as DkgExecuteMsg;
|
||||
use nym_coconut_dkg_common::types::EncodedBTEPublicKeyWithProof;
|
||||
use nym_coconut_dkg_common::verification_key::VerificationKeyShare;
|
||||
use nym_contracts_common::dealings::ContractSafeBytes;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait DkgSigningClient {
|
||||
async fn execute_dkg_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: DkgExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = DkgExecuteMsg::AdvanceEpochState {};
|
||||
|
||||
self.execute_dkg_contract(fee, req, "advancing DKG state".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn surpass_threshold(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = DkgExecuteMsg::SurpassedThreshold {};
|
||||
|
||||
self.execute_dkg_contract(fee, req, "surpass DKG threshold".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn register_dealer(
|
||||
&self,
|
||||
bte_key: EncodedBTEPublicKeyWithProof,
|
||||
announce_address: String,
|
||||
resharing: bool,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = DkgExecuteMsg::RegisterDealer {
|
||||
bte_key_with_proof: bte_key,
|
||||
announce_address,
|
||||
resharing,
|
||||
};
|
||||
|
||||
self.execute_dkg_contract(fee, req, "registering as a dealer".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn submit_dealing_bytes(
|
||||
&self,
|
||||
dealing_bytes: ContractSafeBytes,
|
||||
resharing: bool,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = DkgExecuteMsg::CommitDealing {
|
||||
dealing_bytes,
|
||||
resharing,
|
||||
};
|
||||
|
||||
self.execute_dkg_contract(fee, req, "dealing commitment".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn submit_verification_key_share(
|
||||
&self,
|
||||
share: VerificationKeyShare,
|
||||
resharing: bool,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = DkgExecuteMsg::CommitVerificationKeyShare { share, resharing };
|
||||
|
||||
self.execute_dkg_contract(
|
||||
fee,
|
||||
req,
|
||||
"verification key share commitment".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn verify_verification_key_share(
|
||||
&self,
|
||||
owner: &AccountId,
|
||||
resharing: bool,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
// the call to unchecked is fine as we're converting from pre-validated `AccountId`
|
||||
let owner = Addr::unchecked(owner.to_string());
|
||||
let req = DkgExecuteMsg::VerifyVerificationKeyShare { owner, resharing };
|
||||
|
||||
self.execute_dkg_contract(
|
||||
fee,
|
||||
req,
|
||||
"verification key VerifyVerificationKeyShare".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> DkgSigningClient for C
|
||||
where
|
||||
C: SigningCosmWasmClient + NymContractsProvider + Sync,
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
async fn execute_dkg_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: DkgExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let dkg_contract_address = self
|
||||
.dkg_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("dkg contract"))?;
|
||||
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
|
||||
let signer_address = &self.signer_addresses()?[0];
|
||||
|
||||
self.execute(signer_address, dkg_contract_address, &msg, fee, memo, funds)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_execute_variants_are_covered<C: DkgSigningClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: DkgExecuteMsg,
|
||||
) {
|
||||
match msg {
|
||||
DkgExecuteMsg::RegisterDealer {
|
||||
bte_key_with_proof,
|
||||
announce_address,
|
||||
resharing,
|
||||
} => client
|
||||
.register_dealer(bte_key_with_proof, announce_address, resharing, None)
|
||||
.ignore(),
|
||||
DkgExecuteMsg::CommitDealing {
|
||||
dealing_bytes,
|
||||
resharing,
|
||||
} => client
|
||||
.submit_dealing_bytes(dealing_bytes, resharing, None)
|
||||
.ignore(),
|
||||
DkgExecuteMsg::CommitVerificationKeyShare { share, resharing } => client
|
||||
.submit_verification_key_share(share, resharing, None)
|
||||
.ignore(),
|
||||
DkgExecuteMsg::VerifyVerificationKeyShare { owner, resharing } => client
|
||||
.verify_verification_key_share(
|
||||
&owner.into_string().parse().unwrap(),
|
||||
resharing,
|
||||
None,
|
||||
)
|
||||
.ignore(),
|
||||
DkgExecuteMsg::SurpassedThreshold {} => client.surpass_threshold(None).ignore(),
|
||||
DkgExecuteMsg::AdvanceEpochState {} => client.advance_dkg_epoch_state(None).ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::collect_paged;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use nym_ephemera_common::msg::QueryMsg as EphemeraQueryMsg;
|
||||
use nym_ephemera_common::peers::PagedPeerResponse;
|
||||
use nym_ephemera_common::types::JsonPeerInfo;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait EphemeraQueryClient {
|
||||
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn get_peers_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedPeerResponse, NyxdError> {
|
||||
let request = EphemeraQueryMsg::GetPeers { start_after, limit };
|
||||
self.query_ephemera_contract(request).await
|
||||
}
|
||||
}
|
||||
|
||||
// extension trait to the query client to deal with the paged queries
|
||||
// (it didn't feel appropriate to combine it with the existing trait
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedEphemeraQueryClient: EphemeraQueryClient {
|
||||
async fn get_all_ephemera_peers(&self) -> Result<Vec<JsonPeerInfo>, NyxdError> {
|
||||
collect_paged!(self, get_peers_paged, peers)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedEphemeraQueryClient for T where T: EphemeraQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> EphemeraQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let ephemera_contract_address = &self
|
||||
.ephemera_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
|
||||
self.query_contract_smart(ephemera_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: EphemeraQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: EphemeraQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
EphemeraQueryMsg::GetPeers { limit, start_after } => {
|
||||
client.get_peers_paged(start_after, limit).ignore()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
|
||||
use crate::signing::signer::OfflineSigner;
|
||||
use async_trait::async_trait;
|
||||
use nym_ephemera_common::msg::ExecuteMsg as EphemeraExecuteMsg;
|
||||
use nym_ephemera_common::types::JsonPeerInfo;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait EphemeraSigningClient {
|
||||
async fn execute_ephemera_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: EphemeraExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn register_as_peer(
|
||||
&self,
|
||||
peer_info: JsonPeerInfo,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = EphemeraExecuteMsg::RegisterPeer { peer_info };
|
||||
|
||||
self.execute_ephemera_contract(fee, req, "registering as peer".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> EphemeraSigningClient for C
|
||||
where
|
||||
C: SigningCosmWasmClient + NymContractsProvider + Sync,
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
async fn execute_ephemera_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: EphemeraExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let ephemera_contract_address = self
|
||||
.ephemera_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
|
||||
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
|
||||
let signer_address = &self.signer_addresses()?[0];
|
||||
|
||||
self.execute(
|
||||
signer_address,
|
||||
ephemera_contract_address,
|
||||
&msg,
|
||||
fee,
|
||||
memo,
|
||||
funds,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_execute_variants_are_covered<C: EphemeraSigningClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: EphemeraExecuteMsg,
|
||||
) {
|
||||
match msg {
|
||||
EphemeraExecuteMsg::RegisterPeer { peer_info } => {
|
||||
client.register_as_peer(peer_info, None).ignore()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cw4::{Member, MemberListResponse, MemberResponse, TotalWeightResponse};
|
||||
use nym_group_contract_common::msg::QueryMsg as GroupQueryMsg;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait GroupQueryClient {
|
||||
async fn query_group_contract<T>(&self, query: GroupQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn admin(&self) -> Result<cw_controllers::AdminResponse, NyxdError> {
|
||||
self.query_group_contract(GroupQueryMsg::Admin {}).await
|
||||
}
|
||||
|
||||
async fn total_weight(&self, at_height: Option<u64>) -> Result<TotalWeightResponse, NyxdError> {
|
||||
self.query_group_contract(GroupQueryMsg::TotalWeight { at_height })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_members_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<MemberListResponse, NyxdError> {
|
||||
self.query_group_contract(GroupQueryMsg::ListMembers { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn member(
|
||||
&self,
|
||||
addr: String,
|
||||
at_height: Option<u64>,
|
||||
) -> Result<MemberResponse, NyxdError> {
|
||||
self.query_group_contract(GroupQueryMsg::Member { addr, at_height })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn hooks(&self) -> Result<cw_controllers::HooksResponse, NyxdError> {
|
||||
self.query_group_contract(GroupQueryMsg::Hooks {}).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedGroupQueryClient: GroupQueryClient {
|
||||
// can't use the macro due to different paging behaviour
|
||||
async fn get_all_members(&self) -> Result<Vec<Member>, NyxdError> {
|
||||
let mut members = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self.list_members_paged(start_after.take(), None).await?;
|
||||
|
||||
let last_id = paged_response.members.last().map(|mem| mem.addr.clone());
|
||||
members.append(&mut paged_response.members);
|
||||
|
||||
if let Some(start_after_res) = last_id {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(members)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedGroupQueryClient for T where T: GroupQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> GroupQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_group_contract<T>(&self, query: GroupQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let group_contract_address = &self
|
||||
.group_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("group contract"))?;
|
||||
self.query_contract_smart(group_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: GroupQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: GroupQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
GroupQueryMsg::Admin {} => client.admin().ignore(),
|
||||
GroupQueryMsg::TotalWeight { at_height } => client.total_weight(at_height).ignore(),
|
||||
GroupQueryMsg::ListMembers { start_after, limit } => {
|
||||
client.list_members_paged(start_after, limit).ignore()
|
||||
}
|
||||
GroupQueryMsg::Member { addr, at_height } => client.member(addr, at_height).ignore(),
|
||||
GroupQueryMsg::Hooks {} => client.hooks().ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
|
||||
use crate::signing::signer::OfflineSigner;
|
||||
use async_trait::async_trait;
|
||||
use cw4::Member;
|
||||
use nym_group_contract_common::msg::ExecuteMsg as GroupExecuteMsg;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait GroupSigningClient {
|
||||
async fn execute_group_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: GroupExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn update_admin(
|
||||
&self,
|
||||
admin: Option<String>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_group_contract(
|
||||
fee,
|
||||
GroupExecuteMsg::UpdateAdmin { admin },
|
||||
"GroupExecuteMsg::UpdateAdmin".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update_members(
|
||||
&self,
|
||||
add: Vec<Member>,
|
||||
remove: Vec<String>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_group_contract(
|
||||
fee,
|
||||
GroupExecuteMsg::UpdateMembers { add, remove },
|
||||
"GroupExecuteMsg::UpdateMembers".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn add_hook(&self, addr: String, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_group_contract(
|
||||
fee,
|
||||
GroupExecuteMsg::AddHook { addr },
|
||||
"GroupExecuteMsg::AddHook".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn remove_hook(
|
||||
&self,
|
||||
addr: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_group_contract(
|
||||
fee,
|
||||
GroupExecuteMsg::RemoveHook { addr },
|
||||
"GroupExecuteMsg::RemoveHook".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> GroupSigningClient for C
|
||||
where
|
||||
C: SigningCosmWasmClient + NymContractsProvider + Sync,
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
async fn execute_group_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: GroupExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let group_contract_address = self
|
||||
.group_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("group contract"))?;
|
||||
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
|
||||
|
||||
let signer_address = &self.signer_addresses()?[0];
|
||||
self.execute(
|
||||
signer_address,
|
||||
group_contract_address,
|
||||
&msg,
|
||||
fee,
|
||||
memo,
|
||||
funds,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_execute_variants_are_covered<C: GroupSigningClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: GroupExecuteMsg,
|
||||
) {
|
||||
match msg {
|
||||
GroupExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(),
|
||||
GroupExecuteMsg::UpdateMembers { remove, add } => {
|
||||
client.update_members(add, remove, None).ignore()
|
||||
}
|
||||
GroupExecuteMsg::AddHook { addr } => client.add_hook(addr, None).ignore(),
|
||||
GroupExecuteMsg::RemoveHook { addr } => client.remove_hook(addr, None).ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,745 +0,0 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::collect_paged;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use nym_contracts_common::signing::Nonce;
|
||||
use nym_mixnet_contract_common::{
|
||||
delegation,
|
||||
delegation::{MixNodeDelegationResponse, OwnerProxySubKey},
|
||||
families::{Family, FamilyHead},
|
||||
mixnode::{
|
||||
MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
|
||||
},
|
||||
reward_params::{Performance, RewardingParams},
|
||||
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
|
||||
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
|
||||
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;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait MixnetQueryClient {
|
||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
// state/sys-params-related
|
||||
|
||||
async fn get_mixnet_contract_version(&self) -> Result<ContractBuildInformation, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetContractVersion {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnet_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetCW2ContractVersion {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_rewarding_validator_address(&self) -> Result<AccountId, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetRewardingValidatorAddress {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnet_contract_settings(&self) -> Result<ContractStateParams, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetStateParams {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnet_contract_state_params(&self) -> Result<ContractStateParams, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetStateParams {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnet_contract_state(&self) -> Result<ContractState, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetState {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_rewarding_parameters(&self) -> Result<RewardingParams, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetRewardingParams {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_current_epoch_status(&self) -> Result<EpochStatus, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetEpochStatus {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_current_interval_details(&self) -> Result<CurrentIntervalResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetCurrentIntervalDetails {})
|
||||
.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<MixId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedMixnodeBondsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnodes_detailed_paged(
|
||||
&self,
|
||||
start_after: Option<MixId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedMixnodesDetailsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_unbonded_paged(
|
||||
&self,
|
||||
start_after: Option<MixId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_unbonded_by_owner_paged(
|
||||
&self,
|
||||
owner: &AccountId,
|
||||
start_after: Option<MixId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner {
|
||||
owner: owner.to_string(),
|
||||
limit,
|
||||
start_after,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_unbonded_by_identity_paged(
|
||||
&self,
|
||||
identity_key: IdentityKeyRef<'_>,
|
||||
start_after: Option<MixId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
|
||||
identity_key: identity_key.to_string(),
|
||||
limit,
|
||||
start_after,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_owned_mixnode(
|
||||
&self,
|
||||
address: &AccountId,
|
||||
) -> Result<MixOwnershipResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetOwnedMixnode {
|
||||
address: address.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnode_details(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeDetailsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnode_details_by_identity(
|
||||
&self,
|
||||
mix_identity: IdentityKey,
|
||||
) -> Result<MixnodeDetailsByIdentityResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity {
|
||||
mix_identity,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnode_rewarding_details(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeRewardingDetailsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnode_stake_saturation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<StakeSaturationResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_unbonded_mixnode_information(
|
||||
&self,
|
||||
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::GetLayerDistribution {})
|
||||
.await
|
||||
}
|
||||
|
||||
// gateway-related:
|
||||
|
||||
async fn get_gateways_paged(
|
||||
&self,
|
||||
start_after: Option<IdentityKey>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedGatewayResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetGateways { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Checks whether there is a bonded gateway associated with the provided identity key
|
||||
async fn get_gateway_bond(
|
||||
&self,
|
||||
identity: IdentityKey,
|
||||
) -> Result<GatewayBondResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetGatewayBond { identity })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Checks whether there is a bonded gateway associated with the provided client's address
|
||||
async fn get_owned_gateway(
|
||||
&self,
|
||||
address: &AccountId,
|
||||
) -> Result<GatewayOwnershipResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetOwnedGateway {
|
||||
address: address.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// delegation-related:
|
||||
|
||||
/// Gets list of all delegations towards particular mixnode on particular page.
|
||||
async fn get_mixnode_delegations_paged(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedMixNodeDelegationsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDelegations {
|
||||
mix_id,
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets list of all the mixnodes to which a particular address delegated.
|
||||
async fn get_delegator_delegations_paged(
|
||||
&self,
|
||||
delegator: &AccountId,
|
||||
start_after: Option<(MixId, OwnerProxySubKey)>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedDelegatorDelegationsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations {
|
||||
delegator: delegator.to_string(),
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Checks value of delegation of given client towards particular mixnode.
|
||||
async fn get_delegation_details(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
delegator: &AccountId,
|
||||
proxy: Option<String>,
|
||||
) -> Result<MixNodeDelegationResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetDelegationDetails {
|
||||
mix_id,
|
||||
delegator: delegator.to_string(),
|
||||
proxy,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets all the delegations on the entire network
|
||||
async fn get_all_network_delegations_paged(
|
||||
&self,
|
||||
start_after: Option<delegation::StorageKey>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedAllDelegationsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetAllDelegations { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
// rewards related
|
||||
async fn get_pending_operator_reward(
|
||||
&self,
|
||||
operator: &AccountId,
|
||||
) -> Result<PendingRewardResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingOperatorReward {
|
||||
address: operator.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_pending_mixnode_operator_reward(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<PendingRewardResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_pending_delegator_reward(
|
||||
&self,
|
||||
delegator: &AccountId,
|
||||
mix_id: MixId,
|
||||
proxy: Option<String>,
|
||||
) -> Result<PendingRewardResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingDelegatorReward {
|
||||
address: delegator.to_string(),
|
||||
mix_id,
|
||||
proxy,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// given the provided performance, estimate the reward at the end of the current epoch
|
||||
async fn get_estimated_current_epoch_operator_reward(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
estimated_performance: Performance,
|
||||
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
|
||||
mix_id,
|
||||
estimated_performance,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// given the provided performance, estimate the reward at the end of the current epoch
|
||||
async fn get_estimated_current_epoch_delegator_reward(
|
||||
&self,
|
||||
delegator: &AccountId,
|
||||
mix_id: MixId,
|
||||
proxy: Option<String>,
|
||||
estimated_performance: Performance,
|
||||
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
|
||||
address: delegator.to_string(),
|
||||
mix_id,
|
||||
proxy,
|
||||
estimated_performance,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// interval-related
|
||||
|
||||
async fn get_pending_epoch_events_paged(
|
||||
&self,
|
||||
start_after: Option<EpochEventId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PendingEpochEventsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingEpochEvents { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_pending_interval_events_paged(
|
||||
&self,
|
||||
start_after: Option<IntervalEventId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PendingIntervalEventsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingIntervalEvents { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_pending_epoch_event(
|
||||
&self,
|
||||
event_id: EpochEventId,
|
||||
) -> Result<PendingEpochEventResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingEpochEvent { event_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_pending_interval_event(
|
||||
&self,
|
||||
event_id: IntervalEventId,
|
||||
) -> Result<PendingIntervalEventResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingIntervalEvent { event_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_number_of_pending_events(
|
||||
&self,
|
||||
) -> Result<NumberOfPendingEventsResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetNumberOfPendingEvents {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_signing_nonce(&self, address: &AccountId) -> Result<Nonce, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetSigningNonce {
|
||||
address: address.to_string(),
|
||||
})
|
||||
.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
|
||||
// (it didn't feel appropriate to combine it with the existing trait
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedMixnetQueryClient: MixnetQueryClient {
|
||||
async fn get_all_node_families(&self) -> Result<Vec<Family>, NyxdError> {
|
||||
collect_paged!(self, get_all_node_families_paged, families)
|
||||
}
|
||||
|
||||
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_rewarded_set_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, NyxdError> {
|
||||
collect_paged!(self, get_rewarded_set_paged, nodes)
|
||||
}
|
||||
|
||||
async fn get_all_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, NyxdError> {
|
||||
collect_paged!(self, get_mixnode_bonds_paged, nodes)
|
||||
}
|
||||
|
||||
async fn get_all_mixnodes_detailed(&self) -> Result<Vec<MixNodeDetails>, NyxdError> {
|
||||
collect_paged!(self, get_mixnodes_detailed_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<(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<(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_single_mixnode_delegations(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<Vec<Delegation>, NyxdError> {
|
||||
collect_paged!(self, get_mixnode_delegations_paged, delegations, mix_id)
|
||||
}
|
||||
|
||||
async fn get_all_delegator_delegations(
|
||||
&self,
|
||||
delegation_owner: &AccountId,
|
||||
) -> Result<Vec<Delegation>, NyxdError> {
|
||||
collect_paged!(
|
||||
self,
|
||||
get_delegator_delegations_paged,
|
||||
delegations,
|
||||
delegation_owner
|
||||
)
|
||||
}
|
||||
|
||||
async fn get_all_network_delegations(&self) -> Result<Vec<Delegation>, NyxdError> {
|
||||
collect_paged!(self, get_all_network_delegations_paged, delegations)
|
||||
}
|
||||
|
||||
async fn get_all_pending_epoch_events(&self) -> Result<Vec<PendingEpochEvent>, NyxdError> {
|
||||
collect_paged!(self, get_pending_epoch_events_paged, events)
|
||||
}
|
||||
|
||||
async fn get_all_pending_interval_events(
|
||||
&self,
|
||||
) -> Result<Vec<PendingIntervalEvent>, NyxdError> {
|
||||
collect_paged!(self, get_pending_interval_events_paged, events)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedMixnetQueryClient 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
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let mixnet_contract_address = &self
|
||||
.mixnet_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("mixnet contract"))?;
|
||||
self.query_contract_smart(mixnet_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: MixnetQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: MixnetQueryMsg,
|
||||
) -> u32 {
|
||||
match msg {
|
||||
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()
|
||||
}
|
||||
MixnetQueryMsg::GetRewardingValidatorAddress {} => {
|
||||
client.get_rewarding_validator_address().ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetStateParams {} => client.get_mixnet_contract_state_params().ignore(),
|
||||
MixnetQueryMsg::GetState {} => client.get_mixnet_contract_state().ignore(),
|
||||
MixnetQueryMsg::GetRewardingParams {} => client.get_rewarding_parameters().ignore(),
|
||||
MixnetQueryMsg::GetEpochStatus {} => client.get_current_epoch_status().ignore(),
|
||||
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_paged(start_after, limit).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetUnbondedMixNodesByOwner {
|
||||
owner,
|
||||
limit,
|
||||
start_after,
|
||||
} => client
|
||||
.get_unbonded_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
|
||||
identity_key,
|
||||
limit,
|
||||
start_after,
|
||||
} => client
|
||||
.get_unbonded_by_identity_paged(&identity_key, start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetOwnedMixnode { address } => {
|
||||
client.get_owned_mixnode(&address.parse().unwrap()).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetMixnodeDetails { mix_id } => {
|
||||
client.get_mixnode_details(mix_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id } => {
|
||||
client.get_mixnode_rewarding_details(mix_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetStakeSaturation { mix_id } => {
|
||||
client.get_mixnode_stake_saturation(mix_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id } => {
|
||||
client.get_unbonded_mixnode_information(mix_id).ignore()
|
||||
}
|
||||
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()
|
||||
}
|
||||
MixnetQueryMsg::GetGatewayBond { identity } => {
|
||||
client.get_gateway_bond(identity).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetOwnedGateway { address } => {
|
||||
client.get_owned_gateway(&address.parse().unwrap()).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetMixnodeDelegations {
|
||||
mix_id,
|
||||
start_after,
|
||||
limit,
|
||||
} => client
|
||||
.get_mixnode_delegations_paged(mix_id, start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetDelegatorDelegations {
|
||||
delegator,
|
||||
start_after,
|
||||
limit,
|
||||
} => client
|
||||
.get_delegator_delegations_paged(&delegator.parse().unwrap(), start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetDelegationDetails {
|
||||
mix_id,
|
||||
delegator,
|
||||
proxy,
|
||||
} => client
|
||||
.get_delegation_details(mix_id, &delegator.parse().unwrap(), proxy)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetAllDelegations { start_after, limit } => client
|
||||
.get_all_network_delegations_paged(start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetPendingOperatorReward { address } => client
|
||||
.get_pending_operator_reward(&address.parse().unwrap())
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id } => {
|
||||
client.get_pending_mixnode_operator_reward(mix_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetPendingDelegatorReward {
|
||||
address,
|
||||
mix_id,
|
||||
proxy,
|
||||
} => client
|
||||
.get_pending_delegator_reward(&address.parse().unwrap(), mix_id, proxy)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
|
||||
mix_id,
|
||||
estimated_performance,
|
||||
} => client
|
||||
.get_estimated_current_epoch_operator_reward(mix_id, estimated_performance)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
|
||||
address,
|
||||
mix_id,
|
||||
proxy,
|
||||
estimated_performance,
|
||||
} => client
|
||||
.get_estimated_current_epoch_delegator_reward(
|
||||
&address.parse().unwrap(),
|
||||
mix_id,
|
||||
proxy,
|
||||
estimated_performance,
|
||||
)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => client
|
||||
.get_pending_epoch_events_paged(start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetPendingIntervalEvents { limit, start_after } => client
|
||||
.get_pending_interval_events_paged(start_after, limit)
|
||||
.ignore(),
|
||||
MixnetQueryMsg::GetPendingEpochEvent { event_id } => {
|
||||
client.get_pending_epoch_event(event_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetPendingIntervalEvent { event_id } => {
|
||||
client.get_pending_interval_event(event_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetNumberOfPendingEvents {} => {
|
||||
client.get_number_of_pending_events().ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetSigningNonce { address } => {
|
||||
client.get_signing_nonce(&address.parse().unwrap()).ignore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmrs::AccountId;
|
||||
use nym_network_defaults::NymContracts;
|
||||
use std::str::FromStr;
|
||||
|
||||
// TODO: all of those could/should be derived via a macro
|
||||
|
||||
// query clients
|
||||
mod coconut_bandwidth_query_client;
|
||||
mod dkg_query_client;
|
||||
mod ephemera_query_client;
|
||||
mod group_query_client;
|
||||
mod mixnet_query_client;
|
||||
mod multisig_query_client;
|
||||
mod name_service_query_client;
|
||||
mod sp_directory_query_client;
|
||||
mod vesting_query_client;
|
||||
|
||||
// signing clients
|
||||
mod coconut_bandwidth_signing_client;
|
||||
mod dkg_signing_client;
|
||||
mod ephemera_signing_client;
|
||||
mod group_signing_client;
|
||||
mod mixnet_signing_client;
|
||||
mod multisig_signing_client;
|
||||
mod name_service_signing_client;
|
||||
mod sp_directory_signing_client;
|
||||
mod vesting_signing_client;
|
||||
|
||||
// re-export query traits
|
||||
pub use coconut_bandwidth_query_client::{
|
||||
CoconutBandwidthQueryClient, PagedCoconutBandwidthQueryClient,
|
||||
};
|
||||
pub use dkg_query_client::{DkgQueryClient, PagedDkgQueryClient};
|
||||
pub use ephemera_query_client::{EphemeraQueryClient, PagedEphemeraQueryClient};
|
||||
pub use group_query_client::{GroupQueryClient, PagedGroupQueryClient};
|
||||
pub use mixnet_query_client::{MixnetQueryClient, PagedMixnetQueryClient};
|
||||
pub use multisig_query_client::{MultisigQueryClient, PagedMultisigQueryClient};
|
||||
pub use name_service_query_client::{NameServiceQueryClient, PagedNameServiceQueryClient};
|
||||
pub use sp_directory_query_client::{PagedSpDirectoryQueryClient, SpDirectoryQueryClient};
|
||||
pub use vesting_query_client::{PagedVestingQueryClient, VestingQueryClient};
|
||||
|
||||
// re-export signing traits
|
||||
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
|
||||
pub use dkg_signing_client::DkgSigningClient;
|
||||
pub use ephemera_signing_client::EphemeraSigningClient;
|
||||
pub use group_signing_client::GroupSigningClient;
|
||||
pub use mixnet_signing_client::MixnetSigningClient;
|
||||
pub use multisig_signing_client::MultisigSigningClient;
|
||||
pub use name_service_signing_client::NameServiceSigningClient;
|
||||
pub use sp_directory_signing_client::SpDirectorySigningClient;
|
||||
pub use vesting_signing_client::VestingSigningClient;
|
||||
|
||||
// helper for providing blanket implementation for query clients
|
||||
pub trait NymContractsProvider {
|
||||
// main
|
||||
fn mixnet_contract_address(&self) -> Option<&AccountId>;
|
||||
fn vesting_contract_address(&self) -> Option<&AccountId>;
|
||||
|
||||
// coconut-related
|
||||
fn coconut_bandwidth_contract_address(&self) -> Option<&AccountId>;
|
||||
fn dkg_contract_address(&self) -> Option<&AccountId>;
|
||||
fn group_contract_address(&self) -> Option<&AccountId>;
|
||||
fn multisig_contract_address(&self) -> Option<&AccountId>;
|
||||
|
||||
// ephemera-related
|
||||
fn ephemera_contract_address(&self) -> Option<&AccountId>;
|
||||
|
||||
// SPs
|
||||
fn name_service_contract_address(&self) -> Option<&AccountId>;
|
||||
fn service_provider_contract_address(&self) -> Option<&AccountId>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypedNymContracts {
|
||||
pub mixnet_contract_address: Option<AccountId>,
|
||||
pub vesting_contract_address: Option<AccountId>,
|
||||
|
||||
pub coconut_bandwidth_contract_address: Option<AccountId>,
|
||||
pub group_contract_address: Option<AccountId>,
|
||||
pub multisig_contract_address: Option<AccountId>,
|
||||
pub coconut_dkg_contract_address: Option<AccountId>,
|
||||
|
||||
pub ephemera_contract_address: Option<AccountId>,
|
||||
|
||||
pub service_provider_directory_contract_address: Option<AccountId>,
|
||||
pub name_service_contract_address: Option<AccountId>,
|
||||
}
|
||||
|
||||
impl TryFrom<NymContracts> for TypedNymContracts {
|
||||
type Error = <AccountId as FromStr>::Err;
|
||||
|
||||
fn try_from(value: NymContracts) -> Result<Self, Self::Error> {
|
||||
Ok(TypedNymContracts {
|
||||
mixnet_contract_address: value
|
||||
.mixnet_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
vesting_contract_address: value
|
||||
.vesting_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
coconut_bandwidth_contract_address: value
|
||||
.coconut_bandwidth_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
group_contract_address: value
|
||||
.group_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
multisig_contract_address: value
|
||||
.multisig_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
coconut_dkg_contract_address: value
|
||||
.coconut_dkg_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
ephemera_contract_address: value
|
||||
.ephemera_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
service_provider_directory_contract_address: value
|
||||
.service_provider_directory_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
name_service_contract_address: value
|
||||
.name_service_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// a simple helper macro to define to repeatedly call a paged query until a full response is constructed
|
||||
#[macro_export]
|
||||
macro_rules! collect_paged {
|
||||
// TODO: deal with the args in a nicer way
|
||||
( $self:ident, $f: ident, $field: ident ) => {{
|
||||
let mut res = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let paged_response = $self.$f(start_after.take(), None).await?;
|
||||
res.extend(paged_response.$field);
|
||||
|
||||
if let Some(start_next_after) = paged_response.start_next_after {
|
||||
start_after = Some(start_next_after.into())
|
||||
} else {
|
||||
break Ok(res);
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
( $self:ident, $f: ident, $field: ident, $($args:tt),*) => {{
|
||||
let mut res = Vec::new();
|
||||
let mut start_after = None;
|
||||
loop {
|
||||
let paged_response = $self.$f($($args),*, start_after.take(), None).await?;
|
||||
res.extend(paged_response.$field);
|
||||
|
||||
if let Some(start_next_after) = paged_response.start_next_after {
|
||||
start_after = Some(start_next_after.into())
|
||||
} else {
|
||||
break Ok(res);
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::nyxd::Coin;
|
||||
|
||||
pub(crate) trait IgnoreValue {
|
||||
fn ignore(self) -> u32
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
42
|
||||
// reason we're returning a value as opposed to just `()` is that whenever we match on all enums
|
||||
// we don't want to accidentally miss a variant because compiler will treat it the same way
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IgnoreValue for T {}
|
||||
|
||||
pub(crate) fn mock_coin() -> Coin {
|
||||
Coin::new(42, "ufoomp")
|
||||
}
|
||||
}
|
||||
-178
@@ -1,178 +0,0 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cw3::{
|
||||
ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterListResponse,
|
||||
VoterResponse,
|
||||
};
|
||||
use cw_utils::ThresholdResponse;
|
||||
use nym_multisig_contract_common::msg::QueryMsg as MultisigQueryMsg;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait MultisigQueryClient {
|
||||
async fn query_multisig_contract<T>(&self, query: MultisigQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn query_threshold(&self) -> Result<ThresholdResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::Threshold {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn query_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::Proposal { proposal_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_proposals(
|
||||
&self,
|
||||
start_after: Option<u64>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<ProposalListResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::ListProposals { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn reverse_proposals(
|
||||
&self,
|
||||
start_before: Option<u64>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<ProposalListResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::ReverseProposals {
|
||||
start_before,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn query_vote(&self, proposal_id: u64, voter: String) -> Result<VoteResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::Vote { proposal_id, voter })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_votes(
|
||||
&self,
|
||||
proposal_id: u64,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<VoteListResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::ListVotes {
|
||||
proposal_id,
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn query_voter(&self, address: String) -> Result<VoterResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::Voter { address })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_voters(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<VoterListResponse, NyxdError> {
|
||||
self.query_multisig_contract(MultisigQueryMsg::ListVoters { start_after, limit })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn query_config(&self) -> Result<(), NyxdError> {
|
||||
unimplemented!("requires exporting state::Config type")
|
||||
}
|
||||
}
|
||||
|
||||
// extension trait to the query client to deal with the paged queries
|
||||
// (it didn't feel appropriate to combine it with the existing trait
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedMultisigQueryClient: MultisigQueryClient {
|
||||
// can't use the macro due to different paging behaviour
|
||||
async fn get_all_proposals(&self) -> Result<Vec<ProposalResponse>, NyxdError> {
|
||||
let mut proposals = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self.list_proposals(start_after.take(), None).await?;
|
||||
|
||||
let last_id = paged_response.proposals.last().map(|prop| prop.id);
|
||||
proposals.append(&mut paged_response.proposals);
|
||||
|
||||
if let Some(start_after_res) = last_id {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(proposals)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedMultisigQueryClient for T where T: MultisigQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> MultisigQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_multisig_contract<T>(&self, query: MultisigQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let multisig_contract_address = &self
|
||||
.multisig_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("multisig contract"))?;
|
||||
self.query_contract_smart(multisig_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: MultisigQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: MultisigQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
MultisigQueryMsg::Threshold {} => client.query_threshold().ignore(),
|
||||
MultisigQueryMsg::Proposal { proposal_id } => {
|
||||
client.query_proposal(proposal_id).ignore()
|
||||
}
|
||||
MultisigQueryMsg::ListProposals { start_after, limit } => {
|
||||
client.list_proposals(start_after, limit).ignore()
|
||||
}
|
||||
MultisigQueryMsg::ReverseProposals {
|
||||
start_before,
|
||||
limit,
|
||||
} => client.reverse_proposals(start_before, limit).ignore(),
|
||||
MultisigQueryMsg::Vote { proposal_id, voter } => {
|
||||
client.query_vote(proposal_id, voter).ignore()
|
||||
}
|
||||
MultisigQueryMsg::ListVotes {
|
||||
proposal_id,
|
||||
start_after,
|
||||
limit,
|
||||
} => client.list_votes(proposal_id, start_after, limit).ignore(),
|
||||
MultisigQueryMsg::Voter { address } => client.query_voter(address).ignore(),
|
||||
MultisigQueryMsg::ListVoters { start_after, limit } => {
|
||||
client.list_voters(start_after, limit).ignore()
|
||||
}
|
||||
MultisigQueryMsg::Config {} => client.query_config().ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
-192
@@ -1,192 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
|
||||
use crate::signing::signer::OfflineSigner;
|
||||
use async_trait::async_trait;
|
||||
use cosmwasm_std::{to_binary, CosmosMsg, WasmMsg};
|
||||
use cw3::Vote;
|
||||
use cw4::{MemberChangedHookMsg, MemberDiff};
|
||||
use nym_coconut_bandwidth_contract_common::msg::ExecuteMsg as CoconutBandwidthExecuteMsg;
|
||||
use nym_multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait MultisigSigningClient: NymContractsProvider {
|
||||
async fn execute_multisig_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: MultisigExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn propose_release_funds(
|
||||
&self,
|
||||
title: String,
|
||||
blinded_serial_number: String,
|
||||
voucher_value: Coin,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let coconut_bandwidth_contract_address = self
|
||||
.coconut_bandwidth_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("coconut bandwidth contract"))?;
|
||||
|
||||
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
||||
funds: voucher_value.into(),
|
||||
};
|
||||
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||
contract_addr: coconut_bandwidth_contract_address.to_string(),
|
||||
msg: to_binary(&release_funds_req)?,
|
||||
funds: vec![],
|
||||
});
|
||||
let req = MultisigExecuteMsg::Propose {
|
||||
title,
|
||||
description: blinded_serial_number,
|
||||
msgs: vec![release_funds_msg],
|
||||
latest: None,
|
||||
};
|
||||
self.execute_multisig_contract(
|
||||
fee,
|
||||
req,
|
||||
"Multisig::Propose::Execute::ReleaseFunds".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vote_proposal(
|
||||
&self,
|
||||
proposal_id: u64,
|
||||
vote_yes: bool,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let vote = if vote_yes { Vote::Yes } else { Vote::No };
|
||||
let req = MultisigExecuteMsg::Vote { proposal_id, vote };
|
||||
self.execute_multisig_contract(fee, req, "Multisig::Vote".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
// alternative variant to vote_proposal that lets you to abstain and veto a proposal
|
||||
async fn vote(
|
||||
&self,
|
||||
proposal_id: u64,
|
||||
vote: Vote,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_multisig_contract(
|
||||
fee,
|
||||
MultisigExecuteMsg::Vote { proposal_id, vote },
|
||||
"Multisig::Vote".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn execute_proposal(
|
||||
&self,
|
||||
proposal_id: u64,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = MultisigExecuteMsg::Execute { proposal_id };
|
||||
self.execute_multisig_contract(fee, req, "Multisig::Execute".to_string(), vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn close_proposal(
|
||||
&self,
|
||||
proposal_id: u64,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_multisig_contract(
|
||||
fee,
|
||||
MultisigExecuteMsg::Close { proposal_id },
|
||||
"Multisig::Close".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn changed_member_hook(
|
||||
&self,
|
||||
member_diff: Vec<MemberDiff>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_multisig_contract(
|
||||
fee,
|
||||
MultisigExecuteMsg::MemberChangedHook(MemberChangedHookMsg::new(member_diff)),
|
||||
"Multisig::MemberChangedHook".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> MultisigSigningClient for C
|
||||
where
|
||||
C: SigningCosmWasmClient + NymContractsProvider + Sync,
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
async fn execute_multisig_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: MultisigExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let multisig_contract_address = self
|
||||
.multisig_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("multisig contract"))?;
|
||||
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
|
||||
|
||||
let signer_address = &self.signer_addresses()?[0];
|
||||
self.execute(
|
||||
signer_address,
|
||||
multisig_contract_address,
|
||||
&msg,
|
||||
fee,
|
||||
memo,
|
||||
funds,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_execute_variants_are_covered<C: MultisigSigningClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: MultisigExecuteMsg,
|
||||
) {
|
||||
match msg {
|
||||
MultisigExecuteMsg::Propose {
|
||||
title, description, ..
|
||||
} => client
|
||||
.propose_release_funds(title, description, mock_coin(), None)
|
||||
.ignore(),
|
||||
MultisigExecuteMsg::Vote { proposal_id, vote } => {
|
||||
client.vote(proposal_id, vote, None).ignore()
|
||||
}
|
||||
MultisigExecuteMsg::Execute { proposal_id } => {
|
||||
client.execute_proposal(proposal_id, None).ignore()
|
||||
}
|
||||
MultisigExecuteMsg::Close { proposal_id } => {
|
||||
client.close_proposal(proposal_id, None).ignore()
|
||||
}
|
||||
MultisigExecuteMsg::MemberChangedHook(hook_msg) => {
|
||||
client.changed_member_hook(hook_msg.diffs, None).ignore()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::collect_paged;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::{error::NyxdError, CosmWasmClient};
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
|
||||
use nym_name_service_common::{
|
||||
msg::QueryMsg as NameQueryMsg,
|
||||
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
|
||||
Address, NameId, NymName, RegisteredName,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait NameServiceQueryClient {
|
||||
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn get_name_service_config(&self) -> Result<ConfigResponse, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::Config {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_name_entry(&self, name_id: NameId) -> Result<RegisteredName, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::NameId { name_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_names_paged(
|
||||
&self,
|
||||
start_after: Option<NameId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedNamesListResponse, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::All { limit, start_after })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_name_signing_nonce(&self, address: &AccountId) -> Result<Nonce, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::SigningNonce {
|
||||
address: address.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_names_by_owner(&self, owner: AccountId) -> Result<NamesListResponse, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::ByOwner {
|
||||
owner: owner.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_names_by_nym_name(&self, name: NymName) -> Result<NamesListResponse, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::ByName { name })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_names_by_address(&self, address: Address) -> Result<NamesListResponse, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::ByAddress { address })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_name_service_contract_version(
|
||||
&self,
|
||||
) -> Result<ContractBuildInformation, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::GetContractVersion {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_name_service_contract_cw2_version(
|
||||
&self,
|
||||
) -> Result<cw2::ContractVersion, NyxdError> {
|
||||
self.query_name_service_contract(NameQueryMsg::GetCW2ContractVersion {})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedNameServiceQueryClient: NameServiceQueryClient {
|
||||
async fn get_all_names(&self) -> Result<Vec<RegisteredName>, NyxdError> {
|
||||
collect_paged!(self, get_names_paged, names)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedNameServiceQueryClient for T where T: NameServiceQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> NameServiceQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let name_service_contract_address = &self
|
||||
.name_service_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("name service contract"))?;
|
||||
self.query_contract_smart(name_service_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: NameServiceQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: NameQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
NameQueryMsg::NameId { name_id } => client.get_name_entry(name_id).ignore(),
|
||||
NameQueryMsg::ByOwner { owner } => {
|
||||
client.get_names_by_owner(owner.parse().unwrap()).ignore()
|
||||
}
|
||||
NameQueryMsg::ByName { name } => client.get_names_by_nym_name(name).ignore(),
|
||||
NameQueryMsg::ByAddress { address } => client.get_names_by_address(address).ignore(),
|
||||
NameQueryMsg::All { limit, start_after } => {
|
||||
client.get_names_paged(limit, start_after).ignore()
|
||||
}
|
||||
NameQueryMsg::SigningNonce { address } => client
|
||||
.get_name_signing_nonce(&address.parse().unwrap())
|
||||
.ignore(),
|
||||
NameQueryMsg::Config {} => client.get_name_service_config().ignore(),
|
||||
NameQueryMsg::GetContractVersion {} => {
|
||||
client.get_name_service_contract_version().ignore()
|
||||
}
|
||||
NameQueryMsg::GetCW2ContractVersion {} => {
|
||||
client.get_name_service_contract_cw2_version().ignore()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
use crate::collect_paged;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
|
||||
use nym_service_provider_directory_common::{
|
||||
msg::QueryMsg as SpQueryMsg,
|
||||
response::{
|
||||
ConfigResponse, PagedServicesListResponse, ServiceInfoResponse, ServicesListResponse,
|
||||
},
|
||||
NymAddress, Service, ServiceId,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::{error::NyxdError, CosmWasmClient};
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait SpDirectoryQueryClient {
|
||||
async fn query_service_provider_contract<T>(&self, query: SpQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn get_service_config(&self) -> Result<ConfigResponse, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::Config {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_service_info(
|
||||
&self,
|
||||
service_id: ServiceId,
|
||||
) -> Result<ServiceInfoResponse, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::ServiceId { service_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_services_paged(
|
||||
&self,
|
||||
start_after: Option<ServiceId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<PagedServicesListResponse, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::All { limit, start_after })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_services_by_announcer(
|
||||
&self,
|
||||
announcer: AccountId,
|
||||
) -> Result<ServicesListResponse, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::ByAnnouncer {
|
||||
announcer: announcer.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_services_by_nym_address(
|
||||
&self,
|
||||
nym_address: NymAddress,
|
||||
) -> Result<ServicesListResponse, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::ByNymAddress { nym_address })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_sp_contract_version(&self) -> Result<ContractBuildInformation, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::GetContractVersion {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_sp_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::GetCW2ContractVersion {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_service_signing_nonce(&self, address: &AccountId) -> Result<Nonce, NyxdError> {
|
||||
self.query_service_provider_contract(SpQueryMsg::SigningNonce {
|
||||
address: address.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedSpDirectoryQueryClient: SpDirectoryQueryClient {
|
||||
async fn get_all_services(&self) -> Result<Vec<Service>, NyxdError> {
|
||||
collect_paged!(self, get_services_paged, services)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedSpDirectoryQueryClient for T where T: SpDirectoryQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> SpDirectoryQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_service_provider_contract<T>(&self, query: SpQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let sp_directory_contract_address =
|
||||
&self.service_provider_contract_address().ok_or_else(|| {
|
||||
NyxdError::unavailable_contract_address("service provider directory contract")
|
||||
})?;
|
||||
self.query_contract_smart(sp_directory_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: SpDirectoryQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: SpQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
SpQueryMsg::ServiceId { service_id } => client.get_service_info(service_id).ignore(),
|
||||
SpQueryMsg::ByAnnouncer { announcer } => client
|
||||
.get_services_by_announcer(announcer.parse().unwrap())
|
||||
.ignore(),
|
||||
SpQueryMsg::ByNymAddress { nym_address } => {
|
||||
client.get_services_by_nym_address(nym_address).ignore()
|
||||
}
|
||||
SpQueryMsg::All { limit, start_after } => {
|
||||
client.get_services_paged(start_after, limit).ignore()
|
||||
}
|
||||
SpQueryMsg::SigningNonce { address } => client
|
||||
.get_service_signing_nonce(&address.parse().unwrap())
|
||||
.ignore(),
|
||||
SpQueryMsg::Config {} => client.get_service_config().ignore(),
|
||||
SpQueryMsg::GetContractVersion {} => client.get_sp_contract_version().ignore(),
|
||||
SpQueryMsg::GetCW2ContractVersion {} => client.get_sp_contract_cw2_version().ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
+66
-95
@@ -1,16 +1,15 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
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, SequenceResponse, SimulateResponse,
|
||||
Account, Code, CodeDetails, Contract, ContractCodeHistoryEntry, ContractCodeId,
|
||||
SequenceResponse, SimulateResponse,
|
||||
};
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::rpc::TendermintRpcClient;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::cosmwasm::{CodeInfoResponse, ContractCodeHistoryEntry};
|
||||
use cosmrs::proto::cosmos::auth::v1beta1::{QueryAccountRequest, QueryAccountResponse};
|
||||
use cosmrs::proto::cosmos::bank::v1beta1::{
|
||||
QueryAllBalancesRequest, QueryAllBalancesResponse, QueryBalanceRequest, QueryBalanceResponse,
|
||||
@@ -19,61 +18,50 @@ use cosmrs::proto::cosmos::bank::v1beta1::{
|
||||
use cosmrs::proto::cosmos::tx::v1beta1::{
|
||||
SimulateRequest, SimulateResponse as ProtoSimulateResponse,
|
||||
};
|
||||
use cosmrs::proto::cosmwasm::wasm::v1::{
|
||||
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 cosmrs::proto::cosmwasm::wasm::v1::*;
|
||||
use cosmrs::rpc::endpoint::block::Response as BlockResponse;
|
||||
use cosmrs::rpc::endpoint::broadcast;
|
||||
use cosmrs::rpc::endpoint::tx::Response as TxResponse;
|
||||
use cosmrs::rpc::query::Query;
|
||||
use cosmrs::rpc::{self, HttpClient, Order};
|
||||
use cosmrs::tendermint::abci::Transaction;
|
||||
use cosmrs::tendermint::{abci, block, chain};
|
||||
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Tx};
|
||||
use prost::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::time::Duration;
|
||||
use tendermint_rpc::{
|
||||
endpoint::{block::Response as BlockResponse, broadcast, tx::Response as TxResponse},
|
||||
query::Query,
|
||||
Order,
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::sleep;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::Instant;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::std::Instant;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::sleep;
|
||||
|
||||
pub const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
||||
pub const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
#[async_trait]
|
||||
impl CosmWasmClient for cosmrs::rpc::HttpClient {}
|
||||
impl CosmWasmClient for HttpClient {
|
||||
fn broadcast_polling_rate(&self) -> Duration {
|
||||
Duration::from_secs(4)
|
||||
}
|
||||
|
||||
fn broadcast_timeout(&self) -> Duration {
|
||||
Duration::from_secs(60)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait CosmWasmClient: rpc::Client {
|
||||
// this should probably get redesigned, but I'm leaving those like that temporarily to fix
|
||||
// the underlying issue more quickly
|
||||
fn broadcast_polling_rate(&self) -> Duration;
|
||||
fn broadcast_timeout(&self) -> Duration;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait CosmWasmClient: TendermintRpcClient {
|
||||
// helper method to remove duplicate code involved in making abci requests with protobuf messages
|
||||
// TODO: perhaps it should have an additional argument to determine whether the response should
|
||||
// require proof?
|
||||
async fn make_abci_query<Req, Res>(
|
||||
&self,
|
||||
path: Option<String>,
|
||||
path: Option<abci::Path>,
|
||||
req: Req,
|
||||
) -> Result<Res, NyxdError>
|
||||
where
|
||||
Req: Message,
|
||||
Res: Message + Default,
|
||||
{
|
||||
if let Some(ref abci_path) = path {
|
||||
trace!("performing query on abci path {abci_path}")
|
||||
}
|
||||
let mut buf = Vec::with_capacity(req.encoded_len());
|
||||
req.encode(&mut buf)?;
|
||||
|
||||
@@ -93,7 +81,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
|
||||
// TODO: the return type should probably be changed to a non-proto, type-safe Account alternative
|
||||
async fn get_account(&self, address: &AccountId) -> Result<Option<Account>, NyxdError> {
|
||||
let path = Some("/cosmos.auth.v1beta1.Query/Account".to_owned());
|
||||
let path = Some("/cosmos.auth.v1beta1.Query/Account".parse().unwrap());
|
||||
|
||||
let req = QueryAccountRequest {
|
||||
address: address.to_string(),
|
||||
@@ -131,7 +119,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
address: &AccountId,
|
||||
search_denom: String,
|
||||
) -> Result<Option<Coin>, NyxdError> {
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/Balance".to_owned());
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/Balance".parse().unwrap());
|
||||
|
||||
let req = QueryBalanceRequest {
|
||||
address: address.to_string(),
|
||||
@@ -149,7 +137,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
|
||||
async fn get_all_balances(&self, address: &AccountId) -> Result<Vec<Coin>, NyxdError> {
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/AllBalances".to_owned());
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/AllBalances".parse().unwrap());
|
||||
|
||||
let mut raw_balances = Vec::new();
|
||||
let mut pagination = None;
|
||||
@@ -180,7 +168,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
|
||||
async fn get_total_supply(&self) -> Result<Vec<Coin>, NyxdError> {
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/TotalSupply".to_owned());
|
||||
let path = Some("/cosmos.bank.v1beta1.Query/TotalSupply".parse().unwrap());
|
||||
|
||||
let mut supply = Vec::new();
|
||||
let mut pagination = None;
|
||||
@@ -207,7 +195,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
.map_err(|_| NyxdError::SerializationError("Coins".to_owned()))
|
||||
}
|
||||
|
||||
async fn get_tx(&self, id: Hash) -> Result<TxResponse, NyxdError> {
|
||||
async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NyxdError> {
|
||||
Ok(self.tx(id, false).await?)
|
||||
}
|
||||
|
||||
@@ -243,46 +231,30 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
|
||||
/// Broadcast a transaction, returning immediately.
|
||||
async fn broadcast_tx_async<T>(&self, tx: T) -> Result<broadcast::tx_async::Response, NyxdError>
|
||||
where
|
||||
T: Into<Vec<u8>> + Send,
|
||||
{
|
||||
Ok(TendermintRpcClient::broadcast_tx_async(self, tx).await?)
|
||||
async fn broadcast_tx_async(
|
||||
&self,
|
||||
tx: Transaction,
|
||||
) -> Result<broadcast::tx_async::Response, NyxdError> {
|
||||
Ok(rpc::Client::broadcast_tx_async(self, tx).await?)
|
||||
}
|
||||
|
||||
/// Broadcast a transaction, returning the response from `CheckTx`.
|
||||
async fn broadcast_tx_sync<T>(&self, tx: T) -> Result<broadcast::tx_sync::Response, NyxdError>
|
||||
where
|
||||
T: Into<Vec<u8>> + Send,
|
||||
{
|
||||
Ok(TendermintRpcClient::broadcast_tx_sync(self, tx).await?)
|
||||
async fn broadcast_tx_sync(
|
||||
&self,
|
||||
tx: Transaction,
|
||||
) -> Result<broadcast::tx_sync::Response, NyxdError> {
|
||||
Ok(rpc::Client::broadcast_tx_sync(self, tx).await?)
|
||||
}
|
||||
|
||||
/// Broadcast a transaction, returning the response from `DeliverTx`.
|
||||
async fn broadcast_tx_commit<T>(
|
||||
async fn broadcast_tx_commit(
|
||||
&self,
|
||||
tx: T,
|
||||
) -> Result<broadcast::tx_commit::Response, NyxdError>
|
||||
where
|
||||
T: Into<Vec<u8>> + Send,
|
||||
{
|
||||
Ok(TendermintRpcClient::broadcast_tx_commit(self, tx).await?)
|
||||
tx: Transaction,
|
||||
) -> Result<broadcast::tx_commit::Response, NyxdError> {
|
||||
Ok(rpc::Client::broadcast_tx_commit(self, tx).await?)
|
||||
}
|
||||
|
||||
async fn broadcast_tx<T>(
|
||||
&self,
|
||||
tx: T,
|
||||
timeout: impl Into<Option<Duration>> + Send,
|
||||
poll_interval: impl Into<Option<Duration>> + Send,
|
||||
) -> Result<TxResponse, NyxdError>
|
||||
where
|
||||
T: Into<Vec<u8>> + Send,
|
||||
{
|
||||
let timeout = timeout.into().unwrap_or(DEFAULT_BROADCAST_TIMEOUT);
|
||||
let poll_interval = poll_interval
|
||||
.into()
|
||||
.unwrap_or(DEFAULT_BROADCAST_POLLING_RATE);
|
||||
|
||||
async fn broadcast_tx(&self, tx: Transaction) -> Result<TxResponse, NyxdError> {
|
||||
let broadcasted = CosmWasmClient::broadcast_tx_sync(self, tx).await?;
|
||||
|
||||
if broadcasted.code.is_err() {
|
||||
@@ -297,16 +269,16 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
|
||||
let tx_hash = broadcasted.hash;
|
||||
|
||||
let start = Instant::now();
|
||||
let start = tokio::time::Instant::now();
|
||||
loop {
|
||||
log::debug!(
|
||||
"Polling for result of including {} in a block...",
|
||||
broadcasted.hash
|
||||
);
|
||||
if Instant::now().duration_since(start) >= timeout {
|
||||
if tokio::time::Instant::now().duration_since(start) >= self.broadcast_timeout() {
|
||||
return Err(NyxdError::BroadcastTimeout {
|
||||
hash: tx_hash,
|
||||
timeout,
|
||||
timeout: self.broadcast_timeout(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -314,12 +286,12 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
return Ok(poll_res);
|
||||
}
|
||||
|
||||
sleep(poll_interval).await;
|
||||
tokio::time::sleep(self.broadcast_polling_rate()).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_codes(&self) -> Result<Vec<CodeInfoResponse>, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/Codes".to_owned());
|
||||
async fn get_codes(&self) -> Result<Vec<Code>, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/Codes".parse().unwrap());
|
||||
|
||||
let mut raw_codes = Vec::new();
|
||||
let mut pagination = None;
|
||||
@@ -339,14 +311,14 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(raw_codes
|
||||
raw_codes
|
||||
.into_iter()
|
||||
.map(TryFrom::try_from)
|
||||
.collect::<Result<_, _>>()?)
|
||||
.collect::<Result<_, _>>()
|
||||
}
|
||||
|
||||
async fn get_code_details(&self, code_id: ContractCodeId) -> Result<CodeDetails, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/Code".to_owned());
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/Code".parse().unwrap());
|
||||
|
||||
let req = QueryCodeRequest { code_id };
|
||||
|
||||
@@ -361,7 +333,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
}
|
||||
async fn get_contracts(&self, code_id: ContractCodeId) -> Result<Vec<AccountId>, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/ContractsByCode".to_owned());
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/ContractsByCode".parse().unwrap());
|
||||
|
||||
let mut raw_contracts = Vec::new();
|
||||
let mut pagination = None;
|
||||
@@ -392,7 +364,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
|
||||
async fn get_contract(&self, address: &AccountId) -> Result<Contract, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/ContractInfo".to_owned());
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/ContractInfo".parse().unwrap());
|
||||
|
||||
let req = QueryContractInfoRequest {
|
||||
address: address.to_string(),
|
||||
@@ -417,7 +389,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
&self,
|
||||
address: &AccountId,
|
||||
) -> Result<Vec<ContractCodeHistoryEntry>, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/ContractHistory".to_owned());
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/ContractHistory".parse().unwrap());
|
||||
|
||||
let mut raw_entries = Vec::new();
|
||||
let mut pagination = None;
|
||||
@@ -440,10 +412,10 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(raw_entries
|
||||
raw_entries
|
||||
.into_iter()
|
||||
.map(TryFrom::try_from)
|
||||
.collect::<Result<_, _>>()?)
|
||||
.collect::<Result<_, _>>()
|
||||
}
|
||||
|
||||
async fn query_contract_raw(
|
||||
@@ -451,7 +423,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
address: &AccountId,
|
||||
query_data: Vec<u8>,
|
||||
) -> Result<Vec<u8>, NyxdError> {
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/RawContractState".to_owned());
|
||||
let path = Some("/cosmwasm.wasm.v1.Query/RawContractState".parse().unwrap());
|
||||
|
||||
let req = QueryRawContractStateRequest {
|
||||
address: address.to_string(),
|
||||
@@ -492,7 +464,6 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
.make_abci_query::<_, QuerySmartContractStateResponse>(path, req)
|
||||
.await?;
|
||||
|
||||
trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
|
||||
Ok(serde_json::from_slice(&res.data)?)
|
||||
}
|
||||
|
||||
@@ -508,7 +479,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
tx: Option<Tx>,
|
||||
tx_bytes: Vec<u8>,
|
||||
) -> Result<SimulateResponse, NyxdError> {
|
||||
let path = Some("/cosmos.tx.v1beta1.Service/Simulate".to_owned());
|
||||
let path = Some("/cosmos.tx.v1beta1.Service/Simulate".parse().unwrap());
|
||||
|
||||
let req = SimulateRequest {
|
||||
tx: tx.map(Into::into),
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod query_client;
|
||||
pub mod signing_client;
|
||||
|
||||
pub use query_client::CosmWasmClient;
|
||||
pub use signing_client::SigningCosmWasmClient;
|
||||
@@ -3,7 +3,12 @@
|
||||
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse};
|
||||
use tendermint_rpc::endpoint::broadcast;
|
||||
use cosmrs::proto::cosmos::base::v1beta1::Coin as ProtoCoin;
|
||||
use cosmrs::rpc::endpoint::broadcast;
|
||||
use cosmrs::Coin;
|
||||
use flate2::write::GzEncoder;
|
||||
use flate2::Compression;
|
||||
use std::io::Write;
|
||||
|
||||
pub(crate) trait CheckResponse: Sized {
|
||||
fn check_response(self) -> Result<Self, NyxdError>;
|
||||
@@ -16,7 +21,7 @@ impl CheckResponse for broadcast::tx_commit::Response {
|
||||
hash: self.hash,
|
||||
height: Some(self.height),
|
||||
code: self.check_tx.code.value(),
|
||||
raw_log: self.check_tx.log,
|
||||
raw_log: self.check_tx.log.value().to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +30,7 @@ impl CheckResponse for broadcast::tx_commit::Response {
|
||||
hash: self.hash,
|
||||
height: Some(self.height),
|
||||
code: self.deliver_tx.code.value(),
|
||||
raw_log: self.deliver_tx.log,
|
||||
raw_log: self.deliver_tx.log.value().to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,7 +45,7 @@ impl CheckResponse for crate::nyxd::TxResponse {
|
||||
hash: self.hash,
|
||||
height: Some(self.height),
|
||||
code: self.tx_result.code.value(),
|
||||
raw_log: self.tx_result.log,
|
||||
raw_log: self.tx_result.log.value().to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -49,10 +54,6 @@ impl CheckResponse for crate::nyxd::TxResponse {
|
||||
}
|
||||
|
||||
pub(crate) fn compress_wasm_code(code: &[u8]) -> Result<Vec<u8>, NyxdError> {
|
||||
use flate2::write::GzEncoder;
|
||||
use flate2::Compression;
|
||||
use std::io::Write;
|
||||
|
||||
// using compression level 9, same as cosmjs, that optimises for size
|
||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::best());
|
||||
encoder
|
||||
@@ -82,3 +83,14 @@ pub(crate) fn next_page_key(pagination_info: Option<PageResponse>) -> Option<Vec
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn parse_proto_coin_vec(value: Vec<ProtoCoin>) -> Result<Vec<Coin>, NyxdError> {
|
||||
value
|
||||
.into_iter()
|
||||
.map(|proto_coin| {
|
||||
Coin::try_from(&proto_coin).map_err(|_| NyxdError::MalformedCoin {
|
||||
coin_representation: format!("{:?}", proto_coin),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use cosmrs::tendermint::abci;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -48,7 +49,7 @@ fn parse_raw_str_logs(raw: &str) -> Result<Vec<Log>, NyxdError> {
|
||||
Ok(logs)
|
||||
}
|
||||
|
||||
pub fn parse_raw_logs(raw: String) -> Result<Vec<Log>, NyxdError> {
|
||||
pub fn parse_raw_logs(raw: abci::Log) -> Result<Vec<Log>, NyxdError> {
|
||||
parse_raw_str_logs(raw.as_ref())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,158 +1,31 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::cosmwasm_client::client_traits::{CosmWasmClient, SigningCosmWasmClient};
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Config, GasPrice};
|
||||
use crate::rpc::TendermintRpcClient;
|
||||
use crate::signing::{
|
||||
signer::{NoSigner, OfflineSigner},
|
||||
AccountData,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use tendermint_rpc::{Error as TendermintRpcError, SimpleRequest};
|
||||
use crate::nyxd::GasPrice;
|
||||
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl};
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
use cosmrs::rpc::{HttpClient, HttpClientUrl};
|
||||
use cosmrs::tx::{Raw, SignDoc};
|
||||
|
||||
pub mod client_traits;
|
||||
pub mod client;
|
||||
mod helpers;
|
||||
pub mod logs;
|
||||
pub mod signing_client;
|
||||
pub mod types;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SigningClientOptions {
|
||||
gas_price: GasPrice,
|
||||
simulated_gas_multiplier: f32,
|
||||
pub fn connect<U>(endpoint: U) -> Result<HttpClient, NyxdError>
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
Ok(HttpClient::new(endpoint)?)
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Config> for SigningClientOptions {
|
||||
fn from(value: &'a Config) -> Self {
|
||||
SigningClientOptions {
|
||||
gas_price: value.gas_price.clone(),
|
||||
simulated_gas_multiplier: value.simulated_gas_multiplier,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convenience wrapper around query client to allow for optional signing
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MaybeSigningClient<C, S = NoSigner> {
|
||||
client: C,
|
||||
pub fn connect_with_signer<S, U: Clone>(
|
||||
endpoint: U,
|
||||
signer: S,
|
||||
opts: SigningClientOptions,
|
||||
}
|
||||
|
||||
impl<C> MaybeSigningClient<C> {
|
||||
pub(crate) fn new(client: C, opts: SigningClientOptions) -> Self {
|
||||
MaybeSigningClient {
|
||||
client,
|
||||
signer: Default::default(),
|
||||
opts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, S> MaybeSigningClient<C, S> {
|
||||
pub(crate) fn new_signing(client: C, signer: S, opts: SigningClientOptions) -> Self
|
||||
where
|
||||
S: OfflineSigner,
|
||||
{
|
||||
MaybeSigningClient {
|
||||
client,
|
||||
signer,
|
||||
opts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
impl<S> MaybeSigningClient<HttpClient, S> {
|
||||
pub(crate) fn change_endpoint<U>(&mut self, new_endpoint: U) -> Result<(), NyxdError>
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
self.client = HttpClient::new(new_endpoint)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C, S> TendermintRpcClient for MaybeSigningClient<C, S>
|
||||
gas_price: GasPrice,
|
||||
) -> Result<signing_client::Client<S>, NyxdError>
|
||||
where
|
||||
C: TendermintRpcClient + Send + Sync,
|
||||
S: Send + Sync,
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
async fn perform<R>(&self, request: R) -> Result<R::Output, TendermintRpcError>
|
||||
where
|
||||
R: SimpleRequest,
|
||||
{
|
||||
self.client.perform(request).await
|
||||
}
|
||||
signing_client::Client::connect_with_signer(endpoint, signer, gas_price)
|
||||
}
|
||||
|
||||
impl<C, S> OfflineSigner for MaybeSigningClient<C, S>
|
||||
where
|
||||
S: OfflineSigner,
|
||||
{
|
||||
type Error = S::Error;
|
||||
|
||||
fn get_accounts(&self) -> Result<Vec<AccountData>, Self::Error> {
|
||||
self.signer.get_accounts()
|
||||
}
|
||||
|
||||
fn sign_direct_with_account(
|
||||
&self,
|
||||
signer: &AccountData,
|
||||
sign_doc: SignDoc,
|
||||
) -> Result<Raw, Self::Error> {
|
||||
self.signer.sign_direct_with_account(signer, sign_doc)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C, S> CosmWasmClient for MaybeSigningClient<C, S>
|
||||
where
|
||||
C: TendermintRpcClient + Send + Sync,
|
||||
S: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C, S> SigningCosmWasmClient for MaybeSigningClient<C, S>
|
||||
where
|
||||
C: TendermintRpcClient + Send + Sync,
|
||||
S: OfflineSigner + Send + Sync,
|
||||
NyxdError: From<S::Error>,
|
||||
{
|
||||
fn gas_price(&self) -> &GasPrice {
|
||||
&self.opts.gas_price
|
||||
}
|
||||
|
||||
fn simulated_gas_multiplier(&self) -> f32 {
|
||||
self.opts.simulated_gas_multiplier
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// #[cfg(feature = "http-client")]
|
||||
// pub fn connect<U>(endpoint: U) -> Result<MaybeSigningClient<HttpClient>, NyxdError>
|
||||
// where
|
||||
// U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
// {
|
||||
// Ok(HttpClient::new(endpoint)?)
|
||||
// }
|
||||
//
|
||||
// #[cfg(all(feature = "signing", feature = "http-client"))]
|
||||
// pub fn connect_with_signer<S, U: Clone>(
|
||||
// endpoint: U,
|
||||
// signer: S,
|
||||
// gas_price: crate::nyxd::GasPrice,
|
||||
// ) -> Result<MaybeSigningClient<HttpClient, S>, NyxdError>
|
||||
// where
|
||||
// U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
// {
|
||||
// signing_client::Client::connect_with_signer(endpoint, signer, gas_price)
|
||||
// }
|
||||
|
||||
+191
-224
@@ -1,7 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::cosmwasm_client::client_traits::CosmWasmClient;
|
||||
use crate::nyxd::cosmwasm_client::client::CosmWasmClient;
|
||||
use crate::nyxd::cosmwasm_client::helpers::{compress_wasm_code, CheckResponse};
|
||||
use crate::nyxd::cosmwasm_client::logs::{self, parse_raw_logs};
|
||||
use crate::nyxd::cosmwasm_client::types::*;
|
||||
@@ -12,23 +12,26 @@ use crate::signing::signer::OfflineSigner;
|
||||
use crate::signing::tx_signer::TxSigner;
|
||||
use crate::signing::SignerData;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::abci::GasInfo;
|
||||
use cosmrs::bank::MsgSend;
|
||||
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
||||
use cosmrs::feegrant::{
|
||||
AllowedMsgAllowance, BasicAllowance, MsgGrantAllowance, MsgRevokeAllowance,
|
||||
};
|
||||
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
|
||||
use cosmrs::rpc::endpoint::broadcast;
|
||||
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
|
||||
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
|
||||
use cosmrs::tx::{self, Msg};
|
||||
use cosmrs::{cosmwasm, AccountId, Any, Tx};
|
||||
use cosmrs::tx::{self, Msg, Raw};
|
||||
use cosmrs::{cosmwasm, rpc, AccountId, Any, Tx};
|
||||
use log::debug;
|
||||
use serde::Serialize;
|
||||
use sha2::Digest;
|
||||
use sha2::Sha256;
|
||||
use std::convert::TryInto;
|
||||
use std::time::SystemTime;
|
||||
use tendermint_rpc::endpoint::broadcast;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
||||
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
fn empty_fee() -> tx::Fee {
|
||||
tx::Fee {
|
||||
@@ -53,17 +56,18 @@ fn single_unspecified_signer_auth(
|
||||
.auth_info(empty_fee())
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait SigningCosmWasmClient: CosmWasmClient + TxSigner
|
||||
where
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
// TODO: would it somehow be possible to get rid of this method and allow for
|
||||
// blanket implementation for anything that provides CosmWasmClient + TxSigner?
|
||||
#[async_trait]
|
||||
pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
type Signer: OfflineSigner + Send + Sync;
|
||||
|
||||
fn signer(&self) -> &Self::Signer;
|
||||
|
||||
fn gas_price(&self) -> &GasPrice;
|
||||
|
||||
fn simulated_gas_multiplier(&self) -> f32;
|
||||
fn signer_public_key(&self, signer_address: &AccountId) -> Option<tx::SignerPublicKey> {
|
||||
let account = self.signer().find_account(signer_address).ok()?;
|
||||
Some(account.public_key().into())
|
||||
}
|
||||
|
||||
async fn simulate(
|
||||
&self,
|
||||
@@ -119,10 +123,7 @@ where
|
||||
.check_response()?;
|
||||
|
||||
let logs = parse_raw_logs(tx_res.tx_result.log)?;
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
// TODO: should those strings be extracted into some constants?
|
||||
// the reason I think unwrap here is fine is that if the transaction succeeded and those
|
||||
@@ -183,10 +184,8 @@ where
|
||||
.check_response()?;
|
||||
|
||||
let logs = parse_raw_logs(tx_res.tx_result.log)?;
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
// TODO: should those strings be extracted into some constants?
|
||||
// the reason I think unwrap here is fine is that if the transaction succeeded and those
|
||||
// fields do not exist or address is malformed, there's no way we can recover, we're probably connected
|
||||
@@ -213,7 +212,7 @@ where
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<ChangeAdminResult, NyxdError> {
|
||||
let change_admin_msg = sealed::cosmwasm::MsgUpdateAdmin {
|
||||
let change_admin_msg = cosmwasm::MsgUpdateAdmin {
|
||||
sender: sender_address.clone(),
|
||||
new_admin: new_admin.clone(),
|
||||
contract: contract_address.clone(),
|
||||
@@ -226,10 +225,8 @@ where
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
Ok(ChangeAdminResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
@@ -244,7 +241,7 @@ where
|
||||
fee: Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<ChangeAdminResult, NyxdError> {
|
||||
let change_admin_msg = sealed::cosmwasm::MsgClearAdmin {
|
||||
let change_admin_msg = cosmwasm::MsgClearAdmin {
|
||||
sender: sender_address.clone(),
|
||||
contract: contract_address.clone(),
|
||||
}
|
||||
@@ -256,10 +253,8 @@ where
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
Ok(ChangeAdminResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
@@ -293,10 +288,8 @@ where
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
Ok(MigrateResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
transaction_hash: tx_res.hash,
|
||||
@@ -330,13 +323,11 @@ where
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
Ok(ExecuteResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
data: tx_res.tx_result.data.into(),
|
||||
data: tx_res.tx_result.data,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -373,13 +364,11 @@ where
|
||||
.await?
|
||||
.check_response()?;
|
||||
|
||||
let gas_info = GasInfo {
|
||||
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
|
||||
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
|
||||
};
|
||||
let gas_info = GasInfo::new(tx_res.tx_result.gas_wanted, tx_res.tx_result.gas_used);
|
||||
|
||||
Ok(ExecuteResult {
|
||||
logs: parse_raw_logs(tx_res.tx_result.log)?,
|
||||
data: tx_res.tx_result.data.into(),
|
||||
data: tx_res.tx_result.data,
|
||||
transaction_hash: tx_res.hash,
|
||||
gas_info,
|
||||
})
|
||||
@@ -575,9 +564,9 @@ where
|
||||
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
|
||||
let gas = gas_estimation.adjust_gas(multiplier);
|
||||
|
||||
debug!("Gas estimation: {gas_estimation}");
|
||||
debug!("Multiplying the estimation by {multiplier}");
|
||||
debug!("Final gas limit used: {gas}");
|
||||
debug!("Gas estimation: {}", gas_estimation);
|
||||
debug!("Multiplying the estimation by {}", multiplier);
|
||||
debug!("Final gas limit used: {}", gas);
|
||||
|
||||
let fee = self.gas_price() * gas;
|
||||
Ok::<tx::Fee, NyxdError>(tx::Fee::from_amount_and_gas(fee, gas))
|
||||
@@ -613,7 +602,7 @@ where
|
||||
.to_bytes()
|
||||
.map_err(|_| NyxdError::SerializationError("Tx".to_owned()))?;
|
||||
|
||||
CosmWasmClient::broadcast_tx_async(self, tx_bytes).await
|
||||
CosmWasmClient::broadcast_tx_async(self, tx_bytes.into()).await
|
||||
}
|
||||
|
||||
/// Broadcast a transaction, returning the response from `CheckTx`.
|
||||
@@ -633,7 +622,7 @@ where
|
||||
.to_bytes()
|
||||
.map_err(|_| NyxdError::SerializationError("Tx".to_owned()))?;
|
||||
|
||||
CosmWasmClient::broadcast_tx_sync(self, tx_bytes).await
|
||||
CosmWasmClient::broadcast_tx_sync(self, tx_bytes.into()).await
|
||||
}
|
||||
|
||||
/// Broadcast a transaction, returning the response from `DeliverTx`.
|
||||
@@ -654,7 +643,7 @@ where
|
||||
.to_bytes()
|
||||
.map_err(|_| NyxdError::SerializationError("Tx".to_owned()))?;
|
||||
|
||||
CosmWasmClient::broadcast_tx_commit(self, tx_bytes).await
|
||||
CosmWasmClient::broadcast_tx_commit(self, tx_bytes.into()).await
|
||||
}
|
||||
|
||||
/// Broadcast a transaction to the network and monitors its inclusion in a block.
|
||||
@@ -675,7 +664,7 @@ where
|
||||
.to_bytes()
|
||||
.map_err(|_| NyxdError::SerializationError("Tx".to_owned()))?;
|
||||
|
||||
self.broadcast_tx(tx_bytes, None, None).await
|
||||
self.broadcast_tx(tx_bytes.into()).await
|
||||
}
|
||||
|
||||
async fn sign(
|
||||
@@ -698,177 +687,155 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
Ok(<Self as TxSigner>::sign_direct(
|
||||
self,
|
||||
signer_address,
|
||||
messages,
|
||||
fee,
|
||||
memo,
|
||||
signer_data,
|
||||
)?)
|
||||
self.sign_direct(signer_address, messages, fee, memo, signer_data)
|
||||
}
|
||||
|
||||
fn sign_amino(
|
||||
&self,
|
||||
signer_address: &AccountId,
|
||||
messages: Vec<Any>,
|
||||
fee: tx::Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
signer_data: SignerData,
|
||||
) -> Result<tx::Raw, NyxdError>;
|
||||
|
||||
fn sign_direct(
|
||||
&self,
|
||||
signer_address: &AccountId,
|
||||
messages: Vec<Any>,
|
||||
fee: tx::Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
signer_data: SignerData,
|
||||
) -> Result<tx::Raw, NyxdError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Client<S> {
|
||||
// TODO: somehow nicely hide this guy if we decide to use our client in offline mode,
|
||||
// maybe just convert it into an option?
|
||||
// or maybe we need another level of indirection. tbd.
|
||||
rpc_client: HttpClient,
|
||||
tx_signer: TxSigner<S>,
|
||||
gas_price: GasPrice,
|
||||
|
||||
broadcast_polling_rate: Duration,
|
||||
broadcast_timeout: Duration,
|
||||
}
|
||||
|
||||
impl<S> Client<S> {
|
||||
pub fn connect_with_signer<U: Clone>(
|
||||
endpoint: U,
|
||||
signer: S,
|
||||
gas_price: GasPrice,
|
||||
) -> Result<Self, NyxdError>
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
let rpc_client = HttpClient::new(endpoint)?;
|
||||
Ok(Client {
|
||||
rpc_client,
|
||||
tx_signer: TxSigner::new(signer),
|
||||
gas_price,
|
||||
broadcast_polling_rate: DEFAULT_BROADCAST_POLLING_RATE,
|
||||
broadcast_timeout: DEFAULT_BROADCAST_TIMEOUT,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn offline(signer: S) -> TxSigner<S>
|
||||
where
|
||||
S: OfflineSigner,
|
||||
{
|
||||
TxSigner::new(signer)
|
||||
}
|
||||
|
||||
pub fn change_endpoint<U>(&mut self, new_endpoint: U) -> Result<(), NyxdError>
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
let new_rpc_client = HttpClient::new(new_endpoint)?;
|
||||
self.rpc_client = new_rpc_client;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn into_signer(self) -> S {
|
||||
self.tx_signer.into_inner_signer()
|
||||
}
|
||||
|
||||
pub fn set_broadcast_polling_rate(&mut self, broadcast_polling_rate: Duration) {
|
||||
self.broadcast_polling_rate = broadcast_polling_rate
|
||||
}
|
||||
|
||||
pub fn set_broadcast_timeout(&mut self, broadcast_timeout: Duration) {
|
||||
self.broadcast_timeout = broadcast_timeout
|
||||
}
|
||||
}
|
||||
|
||||
// a temporary bypass until https://github.com/cosmos/cosmos-rust/pull/419 is merged
|
||||
mod sealed {
|
||||
pub mod cosmwasm {
|
||||
use cosmrs::{proto, tx::Msg, AccountId, ErrorReport, Result};
|
||||
|
||||
/// MsgUpdateAdmin sets a new admin for a smart contract
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct MsgUpdateAdmin {
|
||||
/// Sender is the that actor that signed the messages
|
||||
pub sender: AccountId,
|
||||
|
||||
/// NewAdmin address to be set
|
||||
pub new_admin: AccountId,
|
||||
|
||||
/// Contract is the address of the smart contract
|
||||
pub contract: AccountId,
|
||||
}
|
||||
|
||||
impl Msg for MsgUpdateAdmin {
|
||||
type Proto = proto::cosmwasm::wasm::v1::MsgUpdateAdmin;
|
||||
}
|
||||
|
||||
impl TryFrom<proto::cosmwasm::wasm::v1::MsgUpdateAdmin> for MsgUpdateAdmin {
|
||||
type Error = ErrorReport;
|
||||
|
||||
fn try_from(
|
||||
proto: proto::cosmwasm::wasm::v1::MsgUpdateAdmin,
|
||||
) -> Result<MsgUpdateAdmin> {
|
||||
MsgUpdateAdmin::try_from(&proto)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&proto::cosmwasm::wasm::v1::MsgUpdateAdmin> for MsgUpdateAdmin {
|
||||
type Error = ErrorReport;
|
||||
|
||||
fn try_from(
|
||||
proto: &proto::cosmwasm::wasm::v1::MsgUpdateAdmin,
|
||||
) -> Result<MsgUpdateAdmin> {
|
||||
Ok(MsgUpdateAdmin {
|
||||
sender: proto.sender.parse()?,
|
||||
new_admin: proto.new_admin.parse()?,
|
||||
contract: proto.contract.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MsgUpdateAdmin> for proto::cosmwasm::wasm::v1::MsgUpdateAdmin {
|
||||
fn from(msg: MsgUpdateAdmin) -> proto::cosmwasm::wasm::v1::MsgUpdateAdmin {
|
||||
proto::cosmwasm::wasm::v1::MsgUpdateAdmin::from(&msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&MsgUpdateAdmin> for proto::cosmwasm::wasm::v1::MsgUpdateAdmin {
|
||||
fn from(msg: &MsgUpdateAdmin) -> proto::cosmwasm::wasm::v1::MsgUpdateAdmin {
|
||||
proto::cosmwasm::wasm::v1::MsgUpdateAdmin {
|
||||
sender: msg.sender.to_string(),
|
||||
new_admin: msg.new_admin.to_string(),
|
||||
contract: msg.contract.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// MsgUpdateAdminResponse returns empty data
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct MsgUpdateAdminResponse {}
|
||||
|
||||
impl Msg for MsgUpdateAdminResponse {
|
||||
type Proto = proto::cosmwasm::wasm::v1::MsgUpdateAdminResponse;
|
||||
}
|
||||
|
||||
impl TryFrom<proto::cosmwasm::wasm::v1::MsgUpdateAdminResponse> for MsgUpdateAdminResponse {
|
||||
type Error = ErrorReport;
|
||||
|
||||
fn try_from(
|
||||
_proto: proto::cosmwasm::wasm::v1::MsgUpdateAdminResponse,
|
||||
) -> Result<MsgUpdateAdminResponse> {
|
||||
Ok(MsgUpdateAdminResponse {})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MsgUpdateAdminResponse> for proto::cosmwasm::wasm::v1::MsgUpdateAdminResponse {
|
||||
fn from(
|
||||
_msg: MsgUpdateAdminResponse,
|
||||
) -> proto::cosmwasm::wasm::v1::MsgUpdateAdminResponse {
|
||||
proto::cosmwasm::wasm::v1::MsgUpdateAdminResponse {}
|
||||
}
|
||||
}
|
||||
|
||||
/// MsgClearAdmin removes any admin stored for a smart contract
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct MsgClearAdmin {
|
||||
/// Sender is the that actor that signed the messages
|
||||
pub sender: AccountId,
|
||||
|
||||
/// Contract is the address of the smart contract
|
||||
pub contract: AccountId,
|
||||
}
|
||||
|
||||
impl Msg for MsgClearAdmin {
|
||||
type Proto = proto::cosmwasm::wasm::v1::MsgClearAdmin;
|
||||
}
|
||||
|
||||
impl TryFrom<proto::cosmwasm::wasm::v1::MsgClearAdmin> for MsgClearAdmin {
|
||||
type Error = ErrorReport;
|
||||
|
||||
fn try_from(proto: proto::cosmwasm::wasm::v1::MsgClearAdmin) -> Result<MsgClearAdmin> {
|
||||
MsgClearAdmin::try_from(&proto)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&proto::cosmwasm::wasm::v1::MsgClearAdmin> for MsgClearAdmin {
|
||||
type Error = ErrorReport;
|
||||
|
||||
fn try_from(proto: &proto::cosmwasm::wasm::v1::MsgClearAdmin) -> Result<MsgClearAdmin> {
|
||||
Ok(MsgClearAdmin {
|
||||
sender: proto.sender.parse()?,
|
||||
contract: proto.contract.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MsgClearAdmin> for proto::cosmwasm::wasm::v1::MsgClearAdmin {
|
||||
fn from(msg: MsgClearAdmin) -> proto::cosmwasm::wasm::v1::MsgClearAdmin {
|
||||
proto::cosmwasm::wasm::v1::MsgClearAdmin::from(&msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&MsgClearAdmin> for proto::cosmwasm::wasm::v1::MsgClearAdmin {
|
||||
fn from(msg: &MsgClearAdmin) -> proto::cosmwasm::wasm::v1::MsgClearAdmin {
|
||||
proto::cosmwasm::wasm::v1::MsgClearAdmin {
|
||||
sender: msg.sender.to_string(),
|
||||
contract: msg.contract.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// MsgClearAdminResponse returns empty data
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct MsgClearAdminResponse {}
|
||||
|
||||
impl Msg for MsgClearAdminResponse {
|
||||
type Proto = proto::cosmwasm::wasm::v1::MsgClearAdminResponse;
|
||||
}
|
||||
|
||||
impl TryFrom<proto::cosmwasm::wasm::v1::MsgClearAdminResponse> for MsgClearAdminResponse {
|
||||
type Error = ErrorReport;
|
||||
|
||||
fn try_from(
|
||||
_proto: proto::cosmwasm::wasm::v1::MsgClearAdminResponse,
|
||||
) -> Result<MsgClearAdminResponse> {
|
||||
Ok(MsgClearAdminResponse {})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MsgClearAdminResponse> for proto::cosmwasm::wasm::v1::MsgClearAdminResponse {
|
||||
fn from(
|
||||
_msg: MsgClearAdminResponse,
|
||||
) -> proto::cosmwasm::wasm::v1::MsgClearAdminResponse {
|
||||
proto::cosmwasm::wasm::v1::MsgClearAdminResponse {}
|
||||
}
|
||||
}
|
||||
#[async_trait]
|
||||
impl<S> rpc::Client for Client<S>
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
async fn perform<R>(&self, request: R) -> Result<R::Response, rpc::Error>
|
||||
where
|
||||
R: SimpleRequest,
|
||||
{
|
||||
self.rpc_client.perform(request).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> CosmWasmClient for Client<S>
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
fn broadcast_polling_rate(&self) -> Duration {
|
||||
self.broadcast_polling_rate
|
||||
}
|
||||
|
||||
fn broadcast_timeout(&self) -> Duration {
|
||||
self.broadcast_timeout
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> SigningCosmWasmClient for Client<S>
|
||||
where
|
||||
S: OfflineSigner + Send + Sync,
|
||||
NyxdError: From<S::Error>,
|
||||
{
|
||||
type Signer = S;
|
||||
|
||||
fn signer(&self) -> &Self::Signer {
|
||||
self.tx_signer.signer()
|
||||
}
|
||||
|
||||
fn gas_price(&self) -> &GasPrice {
|
||||
&self.gas_price
|
||||
}
|
||||
|
||||
fn sign_amino(
|
||||
&self,
|
||||
signer_address: &AccountId,
|
||||
messages: Vec<Any>,
|
||||
fee: tx::Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
signer_data: SignerData,
|
||||
) -> Result<Raw, NyxdError> {
|
||||
Ok(self
|
||||
.tx_signer
|
||||
.sign_amino(signer_address, messages, fee, memo, signer_data)?)
|
||||
}
|
||||
|
||||
fn sign_direct(
|
||||
&self,
|
||||
signer_address: &AccountId,
|
||||
messages: Vec<Any>,
|
||||
fee: tx::Fee,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
signer_data: SignerData,
|
||||
) -> Result<Raw, NyxdError> {
|
||||
Ok(self
|
||||
.tx_signer
|
||||
.sign_direct(signer_address, messages, fee, memo, signer_data)?)
|
||||
}
|
||||
}
|
||||
@@ -3,35 +3,36 @@
|
||||
|
||||
// TODO: There's a significant argument to pull those out of the package and make a PR on https://github.com/cosmos/cosmos-rust/
|
||||
|
||||
use crate::nyxd::cosmwasm_client::helpers::parse_proto_coin_vec;
|
||||
use crate::nyxd::cosmwasm_client::logs::Log;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use cosmrs::auth::{BaseAccount, ModuleAccount};
|
||||
use cosmrs::cosmwasm::{CodeInfoResponse, ContractInfo};
|
||||
use cosmrs::crypto::PublicKey;
|
||||
use cosmrs::proto::cosmos::auth::v1beta1::{
|
||||
BaseAccount as ProtoBaseAccount, ModuleAccount as ProtoModuleAccount,
|
||||
};
|
||||
use cosmrs::proto::cosmos::base::abci::v1beta1::Result as ProtoAbciResult;
|
||||
use cosmrs::proto::cosmos::base::abci::v1beta1::{
|
||||
GasInfo as ProtoGasInfo, Result as ProtoAbciResult,
|
||||
};
|
||||
use cosmrs::proto::cosmos::tx::v1beta1::SimulateResponse as ProtoSimulateResponse;
|
||||
use cosmrs::proto::cosmos::vesting::v1beta1::{
|
||||
BaseVestingAccount as ProtoBaseVestingAccount,
|
||||
ContinuousVestingAccount as ProtoContinuousVestingAccount,
|
||||
DelayedVestingAccount as ProtoDelayedVestingAccount,
|
||||
DelayedVestingAccount as ProtoDelayedVestingAccount, Period as ProtoPeriod,
|
||||
PeriodicVestingAccount as ProtoPeriodicVestingAccount,
|
||||
PermanentLockedAccount as ProtoPermanentLockedAccount,
|
||||
};
|
||||
use cosmrs::tendermint::{abci, Hash};
|
||||
use cosmrs::tx::{AccountNumber, SequenceNumber};
|
||||
use cosmrs::vesting::{
|
||||
BaseVestingAccount, ContinuousVestingAccount, DelayedVestingAccount, PeriodicVestingAccount,
|
||||
PermanentLockedAccount,
|
||||
use cosmrs::proto::cosmwasm::wasm::v1::{
|
||||
CodeInfoResponse, ContractCodeHistoryEntry as ProtoContractCodeHistoryEntry,
|
||||
ContractCodeHistoryOperationType, ContractInfo as ProtoContractInfo,
|
||||
};
|
||||
use cosmrs::{AccountId, Any, Coin as CosmosCoin};
|
||||
use cosmrs::tendermint::abci;
|
||||
use cosmrs::tendermint::abci::Data;
|
||||
use cosmrs::tx::{AccountNumber, Gas, SequenceNumber};
|
||||
use cosmrs::{tx, AccountId, Any, Coin as CosmosCoin};
|
||||
use prost::Message;
|
||||
use serde::Serialize;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
pub use cosmrs::abci::GasInfo;
|
||||
|
||||
pub type ContractCodeId = u64;
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -43,6 +44,215 @@ pub struct SequenceResponse {
|
||||
pub sequence: SequenceNumber,
|
||||
}
|
||||
|
||||
/// BaseAccount defines a base account type. It contains all the necessary fields
|
||||
/// for basic account functionality. Any custom account type should extend this
|
||||
/// type for additional functionality (e.g. vesting).
|
||||
#[derive(Debug)]
|
||||
pub struct BaseAccount {
|
||||
/// Bech32 account address
|
||||
pub address: AccountId,
|
||||
pub pubkey: Option<PublicKey>,
|
||||
pub account_number: AccountNumber,
|
||||
pub sequence: SequenceNumber,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoBaseAccount> for BaseAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoBaseAccount) -> Result<Self, Self::Error> {
|
||||
let address: AccountId = value
|
||||
.address
|
||||
.parse()
|
||||
.map_err(|_| NyxdError::MalformedAccountAddress(value.address.clone()))?;
|
||||
|
||||
let pubkey = value
|
||||
.pub_key
|
||||
.map(PublicKey::try_from)
|
||||
.transpose()
|
||||
.map_err(|_| NyxdError::InvalidPublicKey(address.clone()))?;
|
||||
|
||||
Ok(BaseAccount {
|
||||
address,
|
||||
pubkey,
|
||||
account_number: value.account_number,
|
||||
sequence: value.sequence,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// ModuleAccount defines an account for modules that holds coins on a pool.
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleAccount {
|
||||
pub base_account: Option<BaseAccount>,
|
||||
pub name: String,
|
||||
pub permissions: Vec<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoModuleAccount> for ModuleAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoModuleAccount) -> Result<Self, Self::Error> {
|
||||
let base_account = value.base_account.map(TryFrom::try_from).transpose()?;
|
||||
|
||||
Ok(ModuleAccount {
|
||||
base_account,
|
||||
name: value.name,
|
||||
permissions: value.permissions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// BaseVestingAccount implements the VestingAccount interface. It contains all
|
||||
/// the necessary fields needed for any vesting account implementation.
|
||||
#[derive(Debug)]
|
||||
pub struct BaseVestingAccount {
|
||||
pub base_account: Option<BaseAccount>,
|
||||
pub original_vesting: Vec<CosmosCoin>,
|
||||
pub delegated_free: Vec<CosmosCoin>,
|
||||
pub delegated_vesting: Vec<CosmosCoin>,
|
||||
pub end_time: i64,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoBaseVestingAccount> for BaseVestingAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoBaseVestingAccount) -> Result<Self, Self::Error> {
|
||||
let base_account = value.base_account.map(TryFrom::try_from).transpose()?;
|
||||
|
||||
let original_vesting = parse_proto_coin_vec(value.original_vesting)?;
|
||||
let delegated_free = parse_proto_coin_vec(value.delegated_free)?;
|
||||
let delegated_vesting = parse_proto_coin_vec(value.delegated_vesting)?;
|
||||
|
||||
Ok(BaseVestingAccount {
|
||||
base_account,
|
||||
original_vesting,
|
||||
delegated_free,
|
||||
delegated_vesting,
|
||||
end_time: value.end_time,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// ContinuousVestingAccount implements the VestingAccount interface. It
|
||||
/// continuously vests by unlocking coins linearly with respect to time.
|
||||
#[derive(Debug)]
|
||||
pub struct ContinuousVestingAccount {
|
||||
pub base_vesting_account: Option<BaseVestingAccount>,
|
||||
pub start_time: i64,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoContinuousVestingAccount> for ContinuousVestingAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoContinuousVestingAccount) -> Result<Self, Self::Error> {
|
||||
let base_vesting_account = value
|
||||
.base_vesting_account
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()?;
|
||||
|
||||
Ok(ContinuousVestingAccount {
|
||||
base_vesting_account,
|
||||
start_time: value.start_time,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// DelayedVestingAccount implements the VestingAccount interface. It vests all
|
||||
/// coins after a specific time, but non prior. In other words, it keeps them
|
||||
/// locked until a specified time.
|
||||
#[derive(Debug)]
|
||||
pub struct DelayedVestingAccount {
|
||||
pub base_vesting_account: Option<BaseVestingAccount>,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoDelayedVestingAccount> for DelayedVestingAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoDelayedVestingAccount) -> Result<Self, Self::Error> {
|
||||
let base_vesting_account = value
|
||||
.base_vesting_account
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()?;
|
||||
|
||||
Ok(DelayedVestingAccount {
|
||||
base_vesting_account,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Period defines a length of time and amount of coins that will vest.
|
||||
#[derive(Debug)]
|
||||
pub struct Period {
|
||||
pub length: i64,
|
||||
pub amount: Vec<CosmosCoin>,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoPeriod> for Period {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoPeriod) -> Result<Self, Self::Error> {
|
||||
Ok(Period {
|
||||
length: value.length,
|
||||
amount: parse_proto_coin_vec(value.amount)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// PeriodicVestingAccount implements the VestingAccount interface. It
|
||||
/// periodically vests by unlocking coins during each specified period.
|
||||
#[derive(Debug)]
|
||||
pub struct PeriodicVestingAccount {
|
||||
pub base_vesting_account: Option<BaseVestingAccount>,
|
||||
pub start_time: i64,
|
||||
pub vesting_periods: Vec<Period>,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoPeriodicVestingAccount> for PeriodicVestingAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoPeriodicVestingAccount) -> Result<Self, Self::Error> {
|
||||
let base_vesting_account = value
|
||||
.base_vesting_account
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()?;
|
||||
|
||||
let vesting_periods = value
|
||||
.vesting_periods
|
||||
.into_iter()
|
||||
.map(TryFrom::try_from)
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(PeriodicVestingAccount {
|
||||
base_vesting_account,
|
||||
start_time: value.start_time,
|
||||
vesting_periods,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// PermanentLockedAccount implements the VestingAccount interface. It does
|
||||
/// not ever release coins, locking them indefinitely. Coins in this account can
|
||||
/// still be used for delegating and for governance votes even while locked.
|
||||
#[derive(Debug)]
|
||||
pub struct PermanentLockedAccount {
|
||||
pub base_vesting_account: Option<BaseVestingAccount>,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoPermanentLockedAccount> for PermanentLockedAccount {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoPermanentLockedAccount) -> Result<Self, Self::Error> {
|
||||
let base_vesting_account = value
|
||||
.base_vesting_account
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()?;
|
||||
|
||||
Ok(PermanentLockedAccount {
|
||||
base_vesting_account,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Account {
|
||||
Base(BaseAccount),
|
||||
@@ -125,32 +335,183 @@ impl TryFrom<Any> for Account {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Code {
|
||||
pub code_id: ContractCodeId,
|
||||
|
||||
/// Bech32 account address
|
||||
pub creator: AccountId,
|
||||
|
||||
/// sha256 hash of the code stored
|
||||
pub data_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
impl TryFrom<CodeInfoResponse> for Code {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: CodeInfoResponse) -> Result<Self, Self::Error> {
|
||||
let CodeInfoResponse {
|
||||
code_id,
|
||||
creator,
|
||||
data_hash,
|
||||
} = value;
|
||||
|
||||
let creator = creator
|
||||
.parse()
|
||||
.map_err(|_| NyxdError::MalformedAccountAddress(creator))?;
|
||||
|
||||
Ok(Code {
|
||||
code_id,
|
||||
creator,
|
||||
data_hash,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CodeDetails {
|
||||
pub code_info: CodeInfoResponse,
|
||||
pub code_info: Code,
|
||||
|
||||
/// The original wasm bytes
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CodeDetails {
|
||||
pub fn new(code_info: CodeInfoResponse, data: Vec<u8>) -> Self {
|
||||
pub fn new(code_info: Code, data: Vec<u8>) -> Self {
|
||||
CodeDetails { code_info, data }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ContractInfo {
|
||||
code_id: ContractCodeId,
|
||||
creator: AccountId,
|
||||
admin: Option<AccountId>,
|
||||
label: String,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoContractInfo> for ContractInfo {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoContractInfo) -> Result<Self, Self::Error> {
|
||||
let ProtoContractInfo {
|
||||
code_id,
|
||||
creator,
|
||||
admin,
|
||||
label,
|
||||
..
|
||||
} = value;
|
||||
|
||||
let admin = if admin.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
admin
|
||||
.parse()
|
||||
.map_err(|_| NyxdError::MalformedAccountAddress(admin))?,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(ContractInfo {
|
||||
code_id,
|
||||
creator: creator
|
||||
.parse()
|
||||
.map_err(|_| NyxdError::MalformedAccountAddress(creator))?,
|
||||
admin,
|
||||
label,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Contract {
|
||||
pub address: AccountId,
|
||||
|
||||
pub contract_info: ContractInfo,
|
||||
pub code_id: ContractCodeId,
|
||||
|
||||
/// Bech32 account address
|
||||
pub creator: AccountId,
|
||||
|
||||
/// Bech32-encoded admin address
|
||||
pub admin: Option<AccountId>,
|
||||
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
impl Contract {
|
||||
pub(crate) fn new(address: AccountId, contract_info: ContractInfo) -> Self {
|
||||
Contract {
|
||||
address,
|
||||
contract_info,
|
||||
code_id: contract_info.code_id,
|
||||
creator: contract_info.creator,
|
||||
admin: contract_info.admin,
|
||||
label: contract_info.label,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ContractCodeHistoryEntryOperation {
|
||||
Init,
|
||||
Genesis,
|
||||
Migrate,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ContractCodeHistoryEntry {
|
||||
/// The source of this history entry
|
||||
pub operation: ContractCodeHistoryEntryOperation,
|
||||
pub code_id: ContractCodeId,
|
||||
pub msg_json: String,
|
||||
}
|
||||
|
||||
impl TryFrom<ProtoContractCodeHistoryEntry> for ContractCodeHistoryEntry {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoContractCodeHistoryEntry) -> Result<Self, Self::Error> {
|
||||
let operation = match ContractCodeHistoryOperationType::from_i32(value.operation)
|
||||
.ok_or(NyxdError::InvalidContractHistoryOperation)?
|
||||
{
|
||||
ContractCodeHistoryOperationType::Unspecified => {
|
||||
return Err(NyxdError::InvalidContractHistoryOperation)
|
||||
}
|
||||
ContractCodeHistoryOperationType::Init => ContractCodeHistoryEntryOperation::Init,
|
||||
ContractCodeHistoryOperationType::Genesis => ContractCodeHistoryEntryOperation::Genesis,
|
||||
ContractCodeHistoryOperationType::Migrate => ContractCodeHistoryEntryOperation::Migrate,
|
||||
};
|
||||
|
||||
Ok(ContractCodeHistoryEntry {
|
||||
operation,
|
||||
code_id: value.code_id,
|
||||
msg_json: String::from_utf8(value.msg)
|
||||
.map_err(|_| NyxdError::DeserializationError("Contract history msg".to_owned()))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize)]
|
||||
pub struct GasInfo {
|
||||
/// GasWanted is the maximum units of work we allow this tx to perform.
|
||||
pub gas_wanted: Gas,
|
||||
|
||||
/// GasUsed is the amount of gas actually consumed.
|
||||
pub gas_used: Gas,
|
||||
}
|
||||
|
||||
impl From<ProtoGasInfo> for GasInfo {
|
||||
fn from(value: ProtoGasInfo) -> Self {
|
||||
GasInfo {
|
||||
gas_wanted: value.gas_wanted.into(),
|
||||
gas_used: value.gas_used.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GasInfo {
|
||||
pub fn new(gas_wanted: Gas, gas_used: Gas) -> Self {
|
||||
GasInfo {
|
||||
gas_wanted,
|
||||
gas_used,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,15 +535,31 @@ impl TryFrom<ProtoAbciResult> for AbciResult {
|
||||
type Error = NyxdError;
|
||||
|
||||
fn try_from(value: ProtoAbciResult) -> Result<Self, Self::Error> {
|
||||
let events = value
|
||||
.events
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let mut events = Vec::with_capacity(value.events.len());
|
||||
|
||||
for proto_event in value.events.into_iter() {
|
||||
let type_str = proto_event.r#type;
|
||||
|
||||
let mut attributes = Vec::with_capacity(proto_event.attributes.len());
|
||||
for proto_attribute in proto_event.attributes.into_iter() {
|
||||
let stringified_ked = String::from_utf8(proto_attribute.key)
|
||||
.map_err(|_| NyxdError::DeserializationError("EventAttributeKey".to_owned()))?;
|
||||
let stringified_value = String::from_utf8(proto_attribute.value)
|
||||
.map_err(|_| NyxdError::DeserializationError("EventAttributeKey".to_owned()))?;
|
||||
|
||||
attributes.push(abci::tag::Tag {
|
||||
key: stringified_ked.parse().unwrap(),
|
||||
value: stringified_value.parse().unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
events.push(abci::Event {
|
||||
type_str,
|
||||
attributes,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
Ok(AbciResult {
|
||||
// TODO: make sure this actually works since technically we're converting from 0.37 protobuf definition as opposed to 0.34...
|
||||
data: value.data,
|
||||
log: value.log,
|
||||
events,
|
||||
@@ -201,10 +578,7 @@ impl TryFrom<ProtoSimulateResponse> for SimulateResponse {
|
||||
|
||||
fn try_from(value: ProtoSimulateResponse) -> Result<Self, Self::Error> {
|
||||
Ok(SimulateResponse {
|
||||
gas_info: value
|
||||
.gas_info
|
||||
.map(|gas_info| gas_info.try_into())
|
||||
.transpose()?,
|
||||
gas_info: value.gas_info.map(|gas_info| gas_info.into()),
|
||||
result: value.result.map(|result| result.try_into()).transpose()?,
|
||||
})
|
||||
}
|
||||
@@ -234,7 +608,7 @@ pub struct UploadResult {
|
||||
pub logs: Vec<Log>,
|
||||
|
||||
/// Transaction hash (might be used as transaction ID)
|
||||
pub transaction_hash: Hash,
|
||||
pub transaction_hash: tx::Hash,
|
||||
|
||||
pub gas_info: GasInfo,
|
||||
}
|
||||
@@ -271,7 +645,7 @@ pub struct InstantiateResult {
|
||||
pub logs: Vec<Log>,
|
||||
|
||||
/// Transaction hash (might be used as transaction ID)
|
||||
pub transaction_hash: Hash,
|
||||
pub transaction_hash: tx::Hash,
|
||||
|
||||
pub gas_info: GasInfo,
|
||||
}
|
||||
@@ -281,7 +655,7 @@ pub struct ChangeAdminResult {
|
||||
pub logs: Vec<Log>,
|
||||
|
||||
/// Transaction hash (might be used as transaction ID)
|
||||
pub transaction_hash: Hash,
|
||||
pub transaction_hash: tx::Hash,
|
||||
|
||||
pub gas_info: GasInfo,
|
||||
}
|
||||
@@ -291,7 +665,7 @@ pub struct MigrateResult {
|
||||
pub logs: Vec<Log>,
|
||||
|
||||
/// Transaction hash (might be used as transaction ID)
|
||||
pub transaction_hash: Hash,
|
||||
pub transaction_hash: tx::Hash,
|
||||
|
||||
pub gas_info: GasInfo,
|
||||
}
|
||||
@@ -300,10 +674,10 @@ pub struct MigrateResult {
|
||||
pub struct ExecuteResult {
|
||||
pub logs: Vec<Log>,
|
||||
|
||||
pub data: Vec<u8>,
|
||||
pub data: Data,
|
||||
|
||||
/// Transaction hash (might be used as transaction ID)
|
||||
pub transaction_hash: Hash,
|
||||
pub transaction_hash: tx::Hash,
|
||||
|
||||
pub gas_info: GasInfo,
|
||||
}
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::cosmwasm_client::types::ContractCodeId;
|
||||
use crate::signing::direct_wallet::DirectSecp256k1HdWalletError;
|
||||
use cosmrs::tendermint::Hash;
|
||||
use cosmrs::{
|
||||
tendermint::{abci::Code as AbciCode, block},
|
||||
AccountId,
|
||||
rpc::endpoint::abci_query::AbciQuery,
|
||||
tendermint::{
|
||||
abci::{self, Code as AbciCode},
|
||||
block,
|
||||
},
|
||||
tx, AccountId,
|
||||
};
|
||||
use std::{io, time::Duration};
|
||||
use tendermint_rpc::endpoint::abci_query::AbciQuery;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use cosmrs::tendermint::error::Error as TendermintError;
|
||||
pub use tendermint_rpc::{
|
||||
use crate::signing::direct_wallet::DirectSecp256k1HdWalletError;
|
||||
pub use cosmrs::rpc::{
|
||||
error::{Error as TendermintRpcError, ErrorDetail as TendermintRpcErrorDetail},
|
||||
response_error::{Code, ResponseError},
|
||||
};
|
||||
use std::{io, time::Duration};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NyxdError {
|
||||
@@ -26,12 +27,9 @@ pub enum NyxdError {
|
||||
#[error(transparent)]
|
||||
WalletError(#[from] DirectSecp256k1HdWalletError),
|
||||
|
||||
#[error("There was an issue on the cosmrs side: {0}")]
|
||||
#[error("There was an issue on the cosmrs side - {0}")]
|
||||
CosmrsError(#[from] cosmrs::Error),
|
||||
|
||||
#[error("There was an issue on the cosmrs side: {0}")]
|
||||
CosmrsErrorReport(#[from] cosmrs::ErrorReport),
|
||||
|
||||
#[error("Failed to derive account address")]
|
||||
AccountDerivationError,
|
||||
|
||||
@@ -45,10 +43,7 @@ pub enum NyxdError {
|
||||
InvalidTxHash(String),
|
||||
|
||||
#[error("Tendermint RPC request failed - {0}")]
|
||||
TendermintErrorRpc(#[from] TendermintRpcError),
|
||||
|
||||
#[error("tendermint library failure: {0}")]
|
||||
TendermintError(#[from] TendermintError),
|
||||
TendermintError(#[from] TendermintRpcError),
|
||||
|
||||
#[error("Failed when attempting to serialize data ({0})")]
|
||||
SerializationError(String),
|
||||
@@ -96,7 +91,7 @@ pub enum NyxdError {
|
||||
"Error when broadcasting tx {hash} at height {height:?}. Error occurred during CheckTx phase. Code: {code}; Raw log: {raw_log}"
|
||||
)]
|
||||
BroadcastTxErrorCheckTx {
|
||||
hash: Hash,
|
||||
hash: tx::Hash,
|
||||
height: Option<block::Height>,
|
||||
code: u32,
|
||||
raw_log: String,
|
||||
@@ -106,7 +101,7 @@ pub enum NyxdError {
|
||||
"Error when broadcasting tx {hash} at height {height:?}. Error occurred during DeliverTx phase. Code: {code}; Raw log: {raw_log}"
|
||||
)]
|
||||
BroadcastTxErrorDeliverTx {
|
||||
hash: Hash,
|
||||
hash: tx::Hash,
|
||||
height: Option<block::Height>,
|
||||
code: u32,
|
||||
raw_log: String,
|
||||
@@ -121,7 +116,7 @@ pub enum NyxdError {
|
||||
#[error("Abci query failed with code {code} - {log}")]
|
||||
AbciError {
|
||||
code: u32,
|
||||
log: String,
|
||||
log: abci::Log,
|
||||
pretty_log: Option<String>,
|
||||
},
|
||||
|
||||
@@ -135,7 +130,7 @@ pub enum NyxdError {
|
||||
NoBaseAccountInformationAvailable,
|
||||
|
||||
#[error("Transaction with ID {hash} has been submitted but not yet found on the chain. You might want to check for it later. There was a total wait of {} seconds", .timeout.as_secs())]
|
||||
BroadcastTimeout { hash: Hash, timeout: Duration },
|
||||
BroadcastTimeout { hash: tx::Hash, timeout: Duration },
|
||||
|
||||
#[error("Cosmwasm std error: {0}")]
|
||||
CosmwasmStdError(#[from] cosmwasm_std::StdError),
|
||||
@@ -153,7 +148,7 @@ pub fn parse_abci_query_result(query_result: AbciQuery) -> Result<AbciQuery, Nyx
|
||||
match query_result.code {
|
||||
AbciCode::Ok => Ok(query_result),
|
||||
AbciCode::Err(code) => Err(NyxdError::AbciError {
|
||||
code: code.into(),
|
||||
code,
|
||||
log: query_result.log.clone(),
|
||||
pretty_log: try_parse_abci_log(&query_result.log),
|
||||
}),
|
||||
@@ -162,8 +157,11 @@ pub fn parse_abci_query_result(query_result: AbciQuery) -> Result<AbciQuery, Nyx
|
||||
|
||||
// Some of the error strings returned by the query are a bit too technical to present to the
|
||||
// enduser. So we special case some commonly encountered errors.
|
||||
fn try_parse_abci_log(log: &str) -> Option<String> {
|
||||
if log.contains("Maximum amount of locked coins has already been pledged") {
|
||||
fn try_parse_abci_log(log: &abci::Log) -> Option<String> {
|
||||
if log
|
||||
.value()
|
||||
.contains("Maximum amount of locked coins has already been pledged")
|
||||
{
|
||||
Some("Maximum amount of locked tokens has already been used. You can only use up to 10% of your locked tokens for bonding and delegating.".to_string())
|
||||
} else {
|
||||
None
|
||||
@@ -173,7 +171,7 @@ fn try_parse_abci_log(log: &str) -> Option<String> {
|
||||
impl NyxdError {
|
||||
pub fn is_tendermint_response_timeout(&self) -> bool {
|
||||
match &self {
|
||||
NyxdError::TendermintErrorRpc(TendermintRpcError(
|
||||
NyxdError::TendermintError(TendermintRpcError(
|
||||
TendermintRpcErrorDetail::Response(err),
|
||||
_,
|
||||
)) => {
|
||||
@@ -200,7 +198,7 @@ impl NyxdError {
|
||||
|
||||
pub fn is_tendermint_response_duplicate(&self) -> bool {
|
||||
match &self {
|
||||
NyxdError::TendermintErrorRpc(TendermintRpcError(
|
||||
NyxdError::TendermintError(TendermintRpcError(
|
||||
TendermintRpcErrorDetail::Response(err),
|
||||
_,
|
||||
)) => {
|
||||
@@ -221,8 +219,4 @@ impl NyxdError {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unavailable_contract_address<S: Into<String>>(contract_type: S) -> Self {
|
||||
NyxdError::NoContractAddressAvailable(contract_type.into())
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user