Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a02a0526e9 |
@@ -1,36 +0,0 @@
|
|||||||
name: Daily security audit
|
|
||||||
|
|
||||||
on: workflow_dispatch
|
|
||||||
jobs:
|
|
||||||
security_audit:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- uses: actions-rs/audit-check@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
notification:
|
|
||||||
if: ${{ failure() }}
|
|
||||||
needs: security_audit
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Keybase - Node Install
|
|
||||||
run: npm install
|
|
||||||
working-directory: .github/workflows/support-files
|
|
||||||
- name: Keybase - Send Notification
|
|
||||||
env:
|
|
||||||
NYM_NOTIFICATION_KIND: nightly
|
|
||||||
NYM_PROJECT_NAME: "Nym daily audit"
|
|
||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBTECH_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "test"
|
|
||||||
uses: docker://keybaseio/client:stable-node
|
|
||||||
with:
|
|
||||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
|
||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||||
steps:
|
steps:
|
||||||
- name: Install Dependencies (Linux)
|
- name: Install Dependencies (Linux)
|
||||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||||
|
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
name: CI for Network Explorer
|
name: CI for Network Explorer
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'explorer/**'
|
- 'explorer/**'
|
||||||
@@ -76,14 +75,3 @@ jobs:
|
|||||||
uses: docker://keybaseio/client:stable-node
|
uses: docker://keybaseio/client:stable-node
|
||||||
with:
|
with:
|
||||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||||
- name: Deploy
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
uses: easingthemes/ssh-deploy@main
|
|
||||||
env:
|
|
||||||
SSH_PRIVATE_KEY: ${{ secrets.CD_PROD_NE_SSH_PRIVATE_KEY }}
|
|
||||||
ARGS: "-rltgoDzvO --delete"
|
|
||||||
SOURCE: "explorer/dist/"
|
|
||||||
REMOTE_HOST: ${{ secrets.CD_PROD_NE_REMOTE_HOST }}
|
|
||||||
REMOTE_USER: ${{ secrets.CD_PROD_NE_REMOTE_USER }}
|
|
||||||
TARGET: ${{ secrets.CD_PROD_NE_REMOTE_TARGET }}
|
|
||||||
EXCLUDE: "/dist/, /node_modules/"
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
|
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Dependencies (Linux)
|
- name: Install Dependencies (Linux)
|
||||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
@@ -44,12 +44,6 @@ jobs:
|
|||||||
command: build
|
command: build
|
||||||
args: --workspace
|
args: --workspace
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
|
|
||||||
- name: Run all tests
|
- name: Run all tests
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
@@ -107,12 +101,6 @@ jobs:
|
|||||||
command: build
|
command: build
|
||||||
args: --workspace --features=coconut
|
args: --workspace --features=coconut
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
|
|
||||||
- name: Run all tests with coconut enabled
|
- name: Run all tests with coconut enabled
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"os":"ubuntu-latest",
|
|
||||||
"rust":"stable",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"os":"windows-latest",
|
|
||||||
"rust":"stable",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"os":"macos-latest",
|
|
||||||
"rust":"stable",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"os":"ubuntu-latest",
|
|
||||||
"rust":"beta",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"os":"windows-latest",
|
|
||||||
"rust":"beta",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"os":"macos-latest",
|
|
||||||
"rust":"beta",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"os":"ubuntu-latest",
|
|
||||||
"rust":"nightly",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"os":"windows-latest",
|
|
||||||
"rust":"nightly",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"os":"macos-latest",
|
|
||||||
"rust":"nightly",
|
|
||||||
"runOnEvent":"workflow_dispatch"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
name: Nightly builds on dispatch
|
|
||||||
|
|
||||||
on: workflow_dispatch
|
|
||||||
jobs:
|
|
||||||
matrix_prep:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
||||||
steps:
|
|
||||||
# creates the matrix strategy from nightly_build_matrix_includes.json
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- id: set-matrix
|
|
||||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
|
||||||
with:
|
|
||||||
inputFile: '.github/workflows/nightly_build_matrix_on_dispatch.json'
|
|
||||||
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
|
||||||
build:
|
|
||||||
needs: matrix_prep
|
|
||||||
strategy:
|
|
||||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
|
|
||||||
steps:
|
|
||||||
- name: Install Dependencies (Linux)
|
|
||||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Install rust toolchain
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
profile: minimal
|
|
||||||
toolchain: ${{ matrix.rust }}
|
|
||||||
override: true
|
|
||||||
components: rustfmt, clippy
|
|
||||||
|
|
||||||
- name: Build all binaries
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: build
|
|
||||||
args: --workspace
|
|
||||||
|
|
||||||
- name: Run all tests
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: test
|
|
||||||
args: --workspace
|
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
|
|
||||||
- name: Run expensive tests
|
|
||||||
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: test
|
|
||||||
args: --workspace --all-features -- --ignored
|
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --all -- --check
|
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
|
|
||||||
- uses: actions-rs/clippy-check@v1
|
|
||||||
name: Clippy checks
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
args: --all-features
|
|
||||||
|
|
||||||
- name: Run clippy
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.rust != 'nightly' }}
|
|
||||||
with:
|
|
||||||
command: clippy
|
|
||||||
args: --workspace --all-targets -- -D warnings
|
|
||||||
|
|
||||||
- name: Reclaim some disk space
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-latest' }}
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
|
|
||||||
# COCONUT stuff
|
|
||||||
- name: Build all binaries with coconut enabled
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: build
|
|
||||||
args: --workspace --features=coconut
|
|
||||||
|
|
||||||
- name: Run all tests with coconut enabled
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: test
|
|
||||||
args: --workspace --features=coconut
|
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
|
|
||||||
- name: Run clippy with coconut enabled
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.rust != 'nightly' }}
|
|
||||||
with:
|
|
||||||
command: clippy
|
|
||||||
args: --workspace --all-targets --features=coconut -- -D warnings
|
|
||||||
|
|
||||||
# nym-wallet (the rust part)
|
|
||||||
- name: Build nym-wallet rust code
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: build
|
|
||||||
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
|
||||||
|
|
||||||
- name: Run nym-wallet tests
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: test
|
|
||||||
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
|
||||||
|
|
||||||
- name: Check nym-wallet formatting
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
|
|
||||||
|
|
||||||
- name: Run clippy for nym-wallet
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.rust != 'nightly' }}
|
|
||||||
with:
|
|
||||||
command: clippy
|
|
||||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
|
|
||||||
|
|
||||||
notification:
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Collect jobs status
|
|
||||||
uses: technote-space/workflow-conclusion-action@v2
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Keybase - Node Install
|
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
|
||||||
run: npm install
|
|
||||||
working-directory: .github/workflows/support-files
|
|
||||||
- name: Keybase - Send Notification
|
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
|
||||||
env:
|
|
||||||
NYM_NOTIFICATION_KIND: nightly
|
|
||||||
NYM_PROJECT_NAME: "Nym nightly build"
|
|
||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMTECH_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "${{ secrets.KEYBASE_CHANNEL_DEV_CORE_ID }}"
|
|
||||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
|
||||||
uses: docker://keybaseio/client:stable-node
|
|
||||||
with:
|
|
||||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
name: Publish Nym CLI binaries
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
env:
|
|
||||||
NETWORK: mainnet
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish-nym-cli:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [ubuntu-latest, windows-latest, macos-latest]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Check the release tag starts with `nym-cli-`
|
|
||||||
if: startsWith(github.ref, 'refs/tags/nym-cli-') == false && github.event_name != 'workflow_dispatch'
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('Release tag did not start with nym-cli-...')
|
|
||||||
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
|
|
||||||
- name: Build binary
|
|
||||||
run: make build-nym-cli
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: nym-cli-${{ matrix.platform }}
|
|
||||||
path: |
|
|
||||||
target/release/nym-cli*
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
target/release/nym-cli
|
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
name: Publish Nym binaries
|
name: Publish Nym binaries
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
add_tokio_unstable:
|
|
||||||
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
|
|
||||||
required: true
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
@@ -26,16 +18,11 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Check the release tag starts with `nym-binaries-`
|
- name: Check the release tag starts with `nym-binaries-`
|
||||||
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false && github.event_name != 'workflow_dispatch'
|
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false
|
||||||
uses: actions/github-script@v3
|
uses: actions/github-script@v3
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
core.setFailed('Release tag did not start with nym-binaries-...')
|
core.setFailed('Release tag did not start with nym-binaries-...')
|
||||||
|
|
||||||
- name: Sets env vars for tokio if set in manual dispatch inputs
|
|
||||||
run: |
|
|
||||||
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
|
|
||||||
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
|
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
@@ -48,24 +35,8 @@ jobs:
|
|||||||
command: build
|
command: build
|
||||||
args: --workspace --release
|
args: --workspace --release
|
||||||
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: my-artifact
|
|
||||||
path: |
|
|
||||||
target/release/nym-client
|
|
||||||
target/release/nym-gateway
|
|
||||||
target/release/nym-mixnode
|
|
||||||
target/release/nym-socks5-client
|
|
||||||
target/release/nym-validator-api
|
|
||||||
target/release/nym-network-requester
|
|
||||||
target/release/nym-network-statistics
|
|
||||||
target/release/nym-cli
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
- name: Upload to release based on tag name
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
target/release/nym-client
|
target/release/nym-client
|
||||||
@@ -74,5 +45,3 @@ jobs:
|
|||||||
target/release/nym-socks5-client
|
target/release/nym-socks5-client
|
||||||
target/release/nym-validator-api
|
target/release/nym-validator-api
|
||||||
target/release/nym-network-requester
|
target/release/nym-network-requester
|
||||||
target/release/nym-network-statistics
|
|
||||||
target/release/nym-cli
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ async function sendKeybaseMessage(messageBody) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const channel = {
|
const channel = {
|
||||||
name: context.env.KEYBASE_NYMBOT_TEAM || 'nymtech_bot',
|
name: 'nymtech_bot',
|
||||||
membersType: 'team',
|
membersType: 'team',
|
||||||
topicName: context.keybase.channel,
|
topicName: context.keybase.channel,
|
||||||
topic_type: 'CHAT',
|
topic_type: 'CHAT',
|
||||||
|
|||||||
+240
-55
@@ -2,39 +2,16 @@
|
|||||||
|
|
||||||
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## Unreleased
|
|
||||||
|
|
||||||
### Added
|
## [Unreleased]
|
||||||
|
|
||||||
- nym-cli: added CLI tool for interacting with the Nyx blockchain and Nym mixnet smart contracts ([#1577])
|
|
||||||
- validator-client: added `query_contract_smart` and `query_contract_raw` on `NymdClient` ([#1558])
|
|
||||||
- network-requester: added additional Blockstream Green wallet endpoint to `example.allowed.list` ([#1611](https://github.com/nymtech/nym/pull/1611))
|
|
||||||
- common/ledger: new library for communicating with a Ledger device ([#1640])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- validator-api, mixnode, gateway should now prefer values in config.toml over mainnet defaults ([#1645])
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- validator-client: made `fee` argument optional for `execute` and `execute_multiple` ([#1541])
|
|
||||||
- socks5 client: graceful shutdown should fix error on disconnect in nym-connect ([#1591])
|
|
||||||
- wasm-client: fixed build errors on MacOS and changed example JS code to use mainnet ([#1585])
|
|
||||||
|
|
||||||
[#1541]: https://github.com/nymtech/nym/pull/1541
|
|
||||||
[#1558]: https://github.com/nymtech/nym/pull/1558
|
|
||||||
[#1577]: https://github.com/nymtech/nym/pull/1577
|
|
||||||
[#1585]: https://github.com/nymtech/nym/pull/1585
|
|
||||||
[#1591]: https://github.com/nymtech/nym/pull/1591
|
|
||||||
[#1640]: https://github.com/nymtech/nym/pull/1640
|
|
||||||
[#1645]: https://github.com/nymtech/nym/pull/1645
|
|
||||||
|
|
||||||
|
|
||||||
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
|
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
|
||||||
|
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
|
||||||
|
- nym-connect: add ability to select network requester and gateway ([#1427])
|
||||||
|
- nym-connect: add ability to export gateway keys as JSON
|
||||||
|
- nym-connect: add auto updater
|
||||||
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
||||||
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
|
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
|
||||||
- explorer-api: add apy values to `mix_nodes` endpoint
|
- explorer-api: add apy values to `mix_nodes` endpoint
|
||||||
@@ -46,14 +23,10 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
- validator-api: add Swagger to document the REST API ([#1249]).
|
- validator-api: add Swagger to document the REST API ([#1249]).
|
||||||
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
|
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
|
||||||
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
|
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
|
||||||
- validator-api: add node info cache storing simulated active set inclusion probabilities
|
|
||||||
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
|
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
|
||||||
|
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
|
||||||
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
|
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
|
||||||
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
|
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
|
||||||
- validator-client: add `denom` argument and add simple test for querying an account balance
|
|
||||||
- gateway, validator-api: Checks for coconut credential double spending attempts, taking the coconut bandwidth contract as source of truth ([#1457])
|
|
||||||
- coconut-bandwidth-contract: Record the state of a coconut credential; create specific proposal for releasing funds ([#1457])
|
|
||||||
- inclusion-probability: add simulator for active set inclusion probability
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@@ -64,12 +37,10 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
||||||
- native & socks5 clients: deduplicate big chunks of init logic
|
- native & socks5 clients: deduplicate big chunks of init logic
|
||||||
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
||||||
- explorer-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service ([#1482]).
|
|
||||||
- network-requester: fix filter for suffix-only domains ([#1487])
|
|
||||||
- validator-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service; cleaner shutdown, without panics ([#1496], [#1573]).
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- nym-connect: reuse config id instead of creating a new id on each connection
|
||||||
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
|
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
|
||||||
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
|
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
|
||||||
- all: updated `rocket` to `0.5.0-rc.2`.
|
- all: updated `rocket` to `0.5.0-rc.2`.
|
||||||
@@ -77,14 +48,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
- gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376])
|
- gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376])
|
||||||
- gateway & mixnode: move detailed build info back to `--version` from `--help`.
|
- gateway & mixnode: move detailed build info back to `--version` from `--help`.
|
||||||
- socks5 client/websocket client: upgrade to latest clap and switched to declarative commandline parsing.
|
- socks5 client/websocket client: upgrade to latest clap and switched to declarative commandline parsing.
|
||||||
- validator-api: fee payment for multisig operations comes from the gateway account instead of the validator APIs' accounts ([#1419])
|
|
||||||
- multisig-contract: Limit the proposal creating functionality to one address (coconut-bandwidth-contract address) ([#1457])
|
|
||||||
- All binaries and cosmwasm blobs are configured at runtime now; binaries are configured using environment variables or .env files and contracts keep the configuration parameters in storage ([#1463])
|
|
||||||
- gateway, network-statistics: include gateway id in the sent statistical data ([#1478])
|
|
||||||
- network explorer: tweak how active set probability is shown ([#1503])
|
|
||||||
- validator-api: rewarder set update fails without panicking on possible nymd queries ([#1520])
|
|
||||||
- network-requester, socks5 client (nym-connect): send and receive respectively a message error to be displayed about filter check failure ([#1576])
|
|
||||||
|
|
||||||
|
|
||||||
[#1249]: https://github.com/nymtech/nym/pull/1249
|
[#1249]: https://github.com/nymtech/nym/pull/1249
|
||||||
[#1256]: https://github.com/nymtech/nym/pull/1256
|
[#1256]: https://github.com/nymtech/nym/pull/1256
|
||||||
@@ -102,19 +65,72 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
[#1329]: https://github.com/nymtech/nym/pull/1329
|
[#1329]: https://github.com/nymtech/nym/pull/1329
|
||||||
[#1353]: https://github.com/nymtech/nym/pull/1353
|
[#1353]: https://github.com/nymtech/nym/pull/1353
|
||||||
[#1376]: https://github.com/nymtech/nym/pull/1376
|
[#1376]: https://github.com/nymtech/nym/pull/1376
|
||||||
|
[#1388]: https://github.com/nymtech/nym/pull/1388
|
||||||
[#1393]: https://github.com/nymtech/nym/pull/1393
|
[#1393]: https://github.com/nymtech/nym/pull/1393
|
||||||
[#1404]: https://github.com/nymtech/nym/pull/1404
|
[#1404]: https://github.com/nymtech/nym/pull/1404
|
||||||
[#1419]: https://github.com/nymtech/nym/pull/1419
|
[#1427]: https://github.com/nymtech/nym/pull/1427
|
||||||
[#1457]: https://github.com/nymtech/nym/pull/1457
|
|
||||||
[#1463]: https://github.com/nymtech/nym/pull/1463
|
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
|
||||||
[#1478]: https://github.com/nymtech/nym/pull/1478
|
|
||||||
[#1482]: https://github.com/nymtech/nym/pull/1482
|
### Added
|
||||||
[#1487]: https://github.com/nymtech/nym/pull/1487
|
|
||||||
[#1496]: https://github.com/nymtech/nym/pull/1496
|
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||||
[#1503]: https://github.com/nymtech/nym/pull/1503
|
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||||
[#1520]: https://github.com/nymtech/nym/pull/1520
|
- mixnet-contract: Added staking_supply field to ContractStateParams.
|
||||||
[#1573]: https://github.com/nymtech/nym/pull/1573
|
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
|
||||||
[#1576]: https://github.com/nymtech/nym/pull/1576
|
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
|
||||||
|
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||||
|
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
|
||||||
|
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
|
||||||
|
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
|
||||||
|
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
|
||||||
|
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
|
||||||
|
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
|
||||||
|
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
|
||||||
|
|
||||||
|
|
||||||
|
[#1255]: https://github.com/nymtech/nym/pull/1255
|
||||||
|
[#1257]: https://github.com/nymtech/nym/pull/1257
|
||||||
|
[#1258]: https://github.com/nymtech/nym/pull/1258
|
||||||
|
[#1275]: https://github.com/nymtech/nym/pull/1275
|
||||||
|
[#1284]: https://github.com/nymtech/nym/pull/1284
|
||||||
|
[#1292]: https://github.com/nymtech/nym/pull/1292
|
||||||
|
[#1331]: https://github.com/nymtech/nym/pull/1331
|
||||||
|
[#1369]: https://github.com/nymtech/nym/pull/1369
|
||||||
|
[#1373]: https://github.com/nymtech/nym/pull/1373
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.6](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.6) (2022-06-21)
|
||||||
|
|
||||||
|
- wallet: undelegating now uses either the mixnet or vesting contract, or both, depending on how delegations were made
|
||||||
|
- wallet: redeeming and compounding now uses both the mixnet and vesting contract
|
||||||
|
- wallet: the wallet backend learned how to archive wallet files
|
||||||
|
- wallet: add ENABLE_QA_MODE environment variable to enable QA mode on built wallet
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14)
|
||||||
|
|
||||||
|
- wallet: add simple CLI tool for decrypting and recovering the wallet file.
|
||||||
|
- wallet: added support for multiple accounts ([#1265])
|
||||||
|
- wallet: compound and claim reward endpoints for operators and delegators ([#1302])
|
||||||
|
- wallet: require password to switch accounts
|
||||||
|
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
|
||||||
|
- wallet: new delegation and rewards UI
|
||||||
|
- wallet: show version in nav bar
|
||||||
|
- wallet: contract admin route put back
|
||||||
|
- wallet: staking_supply field to StateParams
|
||||||
|
- wallet: show transaction hash for redeeming or compounding rewards
|
||||||
|
|
||||||
|
[#1265]: https://github.com/nymtech/nym/pull/1265
|
||||||
|
[#1302]: https://github.com/nymtech/nym/pull/1302
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- all: the default behaviour of validator client is changed to use `broadcast_sync` and poll for transaction inclusion instead of using `broadcast_commit` to deal with timeouts ([#1246])
|
||||||
|
|
||||||
## [v1.0.1](https://github.com/nymtech/nym/tree/v1.0.1) (2022-05-04)
|
## [v1.0.1](https://github.com/nymtech/nym/tree/v1.0.1) (2022-05-04)
|
||||||
|
|
||||||
@@ -147,10 +163,77 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.3...nym-binaries-1.0.0)
|
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.3...nym-binaries-1.0.0)
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.3](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.3) (2022-04-25)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/nym-binaries-1.0.0-rc.2...nym-wallet-v1.0.3)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- \[Issue\] Wallet 1.0.2 cannot send NYM tokens from a DelayedVestingAccount [\#1215](https://github.com/nymtech/nym/issues/1215)
|
||||||
|
- Main README not showing properly with GitHub dark mode [\#1211](https://github.com/nymtech/nym/issues/1211)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Bugfix - wallet undelegation for vesting accounts [\#1220](https://github.com/nymtech/nym/pull/1220) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- Bugfix/delegation reconcile [\#1219](https://github.com/nymtech/nym/pull/1219) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bugfix/query proxied pending delegations [\#1218](https://github.com/nymtech/nym/pull/1218) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Using custom gas multiplier in the wallet [\#1217](https://github.com/nymtech/nym/pull/1217) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/vesting accounts support [\#1216](https://github.com/nymtech/nym/pull/1216) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Release/1.0.0 rc.2 [\#1214](https://github.com/nymtech/nym/pull/1214) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- chore: fix dark mode rendering [\#1212](https://github.com/nymtech/nym/pull/1212) ([pwnfoo](https://github.com/pwnfoo))
|
||||||
|
- Feature/spend coconut [\#1210](https://github.com/nymtech/nym/pull/1210) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Bugfix/unique sphinx key [\#1207](https://github.com/nymtech/nym/pull/1207) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Add cache read and write timeouts [\#1206](https://github.com/nymtech/nym/pull/1206) ([durch](https://github.com/durch))
|
||||||
|
- Additional, more informative routes [\#1204](https://github.com/nymtech/nym/pull/1204) ([durch](https://github.com/durch))
|
||||||
|
- Feature/aggregated econ dynamics explorer endpoint [\#1203](https://github.com/nymtech/nym/pull/1203) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Debugging validator [\#1198](https://github.com/nymtech/nym/pull/1198) ([durch](https://github.com/durch))
|
||||||
|
- wallet: expose additional validator configuration functionality to the frontend [\#1195](https://github.com/nymtech/nym/pull/1195) ([octol](https://github.com/octol))
|
||||||
|
- Update rewarding validator address [\#1193](https://github.com/nymtech/nym/pull/1193) ([durch](https://github.com/durch))
|
||||||
|
- Crypto part of the Groth's NIDKG [\#1182](https://github.com/nymtech/nym/pull/1182) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- fix unbond page [\#1180](https://github.com/nymtech/nym/pull/1180) ([tommyv1987](https://github.com/tommyv1987))
|
||||||
|
- Type safe bounds [\#1179](https://github.com/nymtech/nym/pull/1179) ([durch](https://github.com/durch))
|
||||||
|
- Fix delegation paging [\#1174](https://github.com/nymtech/nym/pull/1174) ([durch](https://github.com/durch))
|
||||||
|
- Update binaries to rc version [\#1172](https://github.com/nymtech/nym/pull/1172) ([tommyv1987](https://github.com/tommyv1987))
|
||||||
|
- Bump ansi-regex from 4.1.0 to 4.1.1 in /docker/typescript\_client/upload\_contract [\#1171](https://github.com/nymtech/nym/pull/1171) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
|
||||||
## [nym-binaries-1.0.0-rc.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.2) (2022-04-15)
|
## [nym-binaries-1.0.0-rc.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.2) (2022-04-15)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.2...nym-binaries-1.0.0-rc.2)
|
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.2...nym-binaries-1.0.0-rc.2)
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.2](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.2) (2022-04-05)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.1...nym-wallet-v1.0.2)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Wallet 1.0.2 visual tweaks [\#1197](https://github.com/nymtech/nym/pull/1197) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- Password for wallet with routes [\#1196](https://github.com/nymtech/nym/pull/1196) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Add auto-updater to Nym Wallet [\#1194](https://github.com/nymtech/nym/pull/1194) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- Fix clippy warnings for beta toolchain [\#1191](https://github.com/nymtech/nym/pull/1191) ([octol](https://github.com/octol))
|
||||||
|
- wallet: expose validator urls to the frontend [\#1190](https://github.com/nymtech/nym/pull/1190) ([octol](https://github.com/octol))
|
||||||
|
- wallet: add test for decrypting stored wallet file [\#1189](https://github.com/nymtech/nym/pull/1189) ([octol](https://github.com/octol))
|
||||||
|
- Fix clippy warnings [\#1188](https://github.com/nymtech/nym/pull/1188) ([octol](https://github.com/octol))
|
||||||
|
- Password for wallet with routes [\#1187](https://github.com/nymtech/nym/pull/1187) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- wallet: add validate\_mnemonic [\#1186](https://github.com/nymtech/nym/pull/1186) ([octol](https://github.com/octol))
|
||||||
|
- wallet: support removing accounts from the wallet file [\#1185](https://github.com/nymtech/nym/pull/1185) ([octol](https://github.com/octol))
|
||||||
|
- Feature/adding discord [\#1184](https://github.com/nymtech/nym/pull/1184) ([gala1234](https://github.com/gala1234))
|
||||||
|
- wallet: config backend for validator selection [\#1183](https://github.com/nymtech/nym/pull/1183) ([octol](https://github.com/octol))
|
||||||
|
- Add storybook to wallet [\#1178](https://github.com/nymtech/nym/pull/1178) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- wallet: connection test nymd and api urls independently [\#1170](https://github.com/nymtech/nym/pull/1170) ([octol](https://github.com/octol))
|
||||||
|
- wallet: wire up account storage [\#1153](https://github.com/nymtech/nym/pull/1153) ([octol](https://github.com/octol))
|
||||||
|
- Feature/signature on deposit [\#1151](https://github.com/nymtech/nym/pull/1151) ([neacsu](https://github.com/neacsu))
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.1](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.1) (2022-04-05)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/nym-binaries-1.0.0-rc.1...nym-wallet-v1.0.1)
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- Check enabling bbbc simultaneously with open access. Estimate what it would take to make this the default compilation target. [\#1175](https://github.com/nymtech/nym/issues/1175)
|
||||||
|
- Get coconut credential for deposited tokens [\#1138](https://github.com/nymtech/nym/issues/1138)
|
||||||
|
- Make payments lazy [\#1135](https://github.com/nymtech/nym/issues/1135)
|
||||||
|
- Uptime on node selection for sets [\#1049](https://github.com/nymtech/nym/issues/1049)
|
||||||
|
|
||||||
## [nym-binaries-1.0.0-rc.1](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.1) (2022-03-28)
|
## [nym-binaries-1.0.0-rc.1](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.1) (2022-03-28)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.0...nym-binaries-1.0.0-rc.1)
|
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.0...nym-binaries-1.0.0-rc.1)
|
||||||
@@ -229,6 +312,108 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
- feature/pedersen-commitments [\#1048](https://github.com/nymtech/nym/pull/1048) ([danielementary](https://github.com/danielementary))
|
- feature/pedersen-commitments [\#1048](https://github.com/nymtech/nym/pull/1048) ([danielementary](https://github.com/danielementary))
|
||||||
- Feature/reuse init owner [\#970](https://github.com/nymtech/nym/pull/970) ([neacsu](https://github.com/neacsu))
|
- Feature/reuse init owner [\#970](https://github.com/nymtech/nym/pull/970) ([neacsu](https://github.com/neacsu))
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.0](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.0) (2022-02-03)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/v0.12.1...nym-wallet-v1.0.0)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- \[Feature Request\] Please enable registration without need for Telegram account [\#1016](https://github.com/nymtech/nym/issues/1016)
|
||||||
|
- Fast mixnode launch with a pre-built ISO + VM software [\#1001](https://github.com/nymtech/nym/issues/1001)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- \[Issue\] [\#1000](https://github.com/nymtech/nym/issues/1000)
|
||||||
|
- \[Issue\] `nym-client` requires multiple attempts to run a server [\#869](https://github.com/nymtech/nym/issues/869)
|
||||||
|
- De-'float'-ing `Interval` \(`Display` impl + `serde`\) [\#1065](https://github.com/nymtech/nym/pull/1065) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- display client address on wallet creation [\#1058](https://github.com/nymtech/nym/pull/1058) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- Rewarded set inclusion probability API endpoint [\#1037](https://github.com/nymtech/nym/issues/1037)
|
||||||
|
- Update cw-storage-plus to 0.11 [\#1032](https://github.com/nymtech/nym/issues/1032)
|
||||||
|
- Change `u128` fields in `RewardEstimationResponse` to `u64` [\#1029](https://github.com/nymtech/nym/issues/1029)
|
||||||
|
- Test out the mainnet Gravity Bridge [\#1006](https://github.com/nymtech/nym/issues/1006)
|
||||||
|
- Add vesting contract interface to nym-wallet [\#959](https://github.com/nymtech/nym/issues/959)
|
||||||
|
- Mixnode crash [\#486](https://github.com/nymtech/nym/issues/486)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- create custom urls for mainnet [\#1095](https://github.com/nymtech/nym/pull/1095) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Wallet signing on MacOS [\#1093](https://github.com/nymtech/nym/pull/1093) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- Fix rust 2018 idioms warnings [\#1092](https://github.com/nymtech/nym/pull/1092) ([octol](https://github.com/octol))
|
||||||
|
- Prevent contract overwriting [\#1090](https://github.com/nymtech/nym/pull/1090) ([durch](https://github.com/durch))
|
||||||
|
- Logout operation [\#1087](https://github.com/nymtech/nym/pull/1087) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Update to rust edition 2021 everywhere [\#1086](https://github.com/nymtech/nym/pull/1086) ([octol](https://github.com/octol))
|
||||||
|
- Tag contract errors, and print out lines for easier QA [\#1084](https://github.com/nymtech/nym/pull/1084) ([durch](https://github.com/durch))
|
||||||
|
- Feature/flexible vesting + utility queries [\#1083](https://github.com/nymtech/nym/pull/1083) ([durch](https://github.com/durch))
|
||||||
|
- Bump @openzeppelin/contracts from 4.3.1 to 4.4.2 in /contracts/basic-bandwidth-generation [\#1082](https://github.com/nymtech/nym/pull/1082) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump nth-check from 2.0.0 to 2.0.1 in /clients/native/examples/js-examples/websocket [\#1081](https://github.com/nymtech/nym/pull/1081) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump url-parse from 1.5.1 to 1.5.4 in /clients/native/examples/js-examples/websocket [\#1080](https://github.com/nymtech/nym/pull/1080) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump follow-redirects from 1.14.1 to 1.14.7 in /clients/native/examples/js-examples/websocket [\#1079](https://github.com/nymtech/nym/pull/1079) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump nanoid from 3.1.23 to 3.2.0 in /clients/native/examples/js-examples/websocket [\#1078](https://github.com/nymtech/nym/pull/1078) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Setup basic test for mixnode stats reporting [\#1077](https://github.com/nymtech/nym/pull/1077) ([octol](https://github.com/octol))
|
||||||
|
- Make wallet\_address mandatory for mixnode init [\#1076](https://github.com/nymtech/nym/pull/1076) ([octol](https://github.com/octol))
|
||||||
|
- Tidy nym-mixnode module visibility [\#1075](https://github.com/nymtech/nym/pull/1075) ([octol](https://github.com/octol))
|
||||||
|
- Feature/wallet login with password [\#1074](https://github.com/nymtech/nym/pull/1074) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Add trait to mock client dependency in DelayForwarder [\#1073](https://github.com/nymtech/nym/pull/1073) ([octol](https://github.com/octol))
|
||||||
|
- Bump rust-version to latest stable for nym-mixnode [\#1072](https://github.com/nymtech/nym/pull/1072) ([octol](https://github.com/octol))
|
||||||
|
- Fixes CI for our wasm build [\#1069](https://github.com/nymtech/nym/pull/1069) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Add @octol as codeowner [\#1068](https://github.com/nymtech/nym/pull/1068) ([octol](https://github.com/octol))
|
||||||
|
- set-up inclusion probability [\#1067](https://github.com/nymtech/nym/pull/1067) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Feature/wasm client [\#1066](https://github.com/nymtech/nym/pull/1066) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Changed bech32\_prefix from punk to nymt [\#1064](https://github.com/nymtech/nym/pull/1064) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump nanoid from 3.1.30 to 3.2.0 in /testnet-faucet [\#1063](https://github.com/nymtech/nym/pull/1063) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump nanoid from 3.1.30 to 3.2.0 in /nym-wallet [\#1062](https://github.com/nymtech/nym/pull/1062) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Rework vesting contract storage [\#1061](https://github.com/nymtech/nym/pull/1061) ([durch](https://github.com/durch))
|
||||||
|
- Mixnet Contract constants extraction [\#1060](https://github.com/nymtech/nym/pull/1060) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- fix: make explorer footer year dynamic [\#1059](https://github.com/nymtech/nym/pull/1059) ([martinyung](https://github.com/martinyung))
|
||||||
|
- Add mnemonic just on creation, to display it [\#1057](https://github.com/nymtech/nym/pull/1057) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Network Explorer: updates to API and UI to show the active set [\#1056](https://github.com/nymtech/nym/pull/1056) ([mmsinclair](https://github.com/mmsinclair))
|
||||||
|
- Made contract addresses for query NymdClient construction optional [\#1055](https://github.com/nymtech/nym/pull/1055) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Introduced RPC query for total token supply [\#1053](https://github.com/nymtech/nym/pull/1053) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/tokio console [\#1052](https://github.com/nymtech/nym/pull/1052) ([durch](https://github.com/durch))
|
||||||
|
- Implemented beta clippy lint recommendations [\#1051](https://github.com/nymtech/nym/pull/1051) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- add new function to update profit percentage [\#1050](https://github.com/nymtech/nym/pull/1050) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Upgrade Clap and use declarative argument parsing for nym-mixnode [\#1047](https://github.com/nymtech/nym/pull/1047) ([octol](https://github.com/octol))
|
||||||
|
- Feature/additional bond validation [\#1046](https://github.com/nymtech/nym/pull/1046) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Fix clippy on relevant lints [\#1044](https://github.com/nymtech/nym/pull/1044) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Bump shelljs from 0.8.4 to 0.8.5 in /contracts/basic-bandwidth-generation [\#1043](https://github.com/nymtech/nym/pull/1043) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Endpoint for rewarded set inclusion probabilities [\#1042](https://github.com/nymtech/nym/pull/1042) ([durch](https://github.com/durch))
|
||||||
|
- Bump follow-redirects from 1.14.4 to 1.14.7 in /contracts/basic-bandwidth-generation [\#1041](https://github.com/nymtech/nym/pull/1041) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump follow-redirects from 1.14.5 to 1.14.7 in /testnet-faucet [\#1040](https://github.com/nymtech/nym/pull/1040) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/node settings update [\#1036](https://github.com/nymtech/nym/pull/1036) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Migrate to cw-storage-plus 0.11.1 [\#1035](https://github.com/nymtech/nym/pull/1035) ([durch](https://github.com/durch))
|
||||||
|
- Bump @openzeppelin/contracts from 4.4.1 to 4.4.2 in /contracts/basic-bandwidth-generation [\#1034](https://github.com/nymtech/nym/pull/1034) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/configurable wallet [\#1033](https://github.com/nymtech/nym/pull/1033) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Feature/downcast reward estimation [\#1031](https://github.com/nymtech/nym/pull/1031) ([durch](https://github.com/durch))
|
||||||
|
- Wallet UI updates [\#1028](https://github.com/nymtech/nym/pull/1028) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Remove migration code [\#1027](https://github.com/nymtech/nym/pull/1027) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Chore/stricter dependency requirements [\#1025](https://github.com/nymtech/nym/pull/1025) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/validator api client endpoints [\#1024](https://github.com/nymtech/nym/pull/1024) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Updated cosmrs to 0.4.1 [\#1023](https://github.com/nymtech/nym/pull/1023) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/testnet deploy scripts [\#1022](https://github.com/nymtech/nym/pull/1022) ([mfahampshire](https://github.com/mfahampshire))
|
||||||
|
- Changed wallet's client to a full validator client [\#1021](https://github.com/nymtech/nym/pull/1021) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fix 404 link [\#1020](https://github.com/nymtech/nym/pull/1020) ([RiccardoMasutti](https://github.com/RiccardoMasutti))
|
||||||
|
- Feature/additional mixnode endpoints [\#1019](https://github.com/nymtech/nym/pull/1019) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Introduced denom check when trying to withdraw vested coins [\#1018](https://github.com/nymtech/nym/pull/1018) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Add network defaults for qa [\#1017](https://github.com/nymtech/nym/pull/1017) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Feature/expanded events [\#1015](https://github.com/nymtech/nym/pull/1015) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- update frontend to use new profit update api [\#1014](https://github.com/nymtech/nym/pull/1014) ([fmtabbara](https://github.com/fmtabbara))
|
||||||
|
- Feature/node state endpoint [\#1013](https://github.com/nymtech/nym/pull/1013) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/hourly set updates [\#1012](https://github.com/nymtech/nym/pull/1012) ([durch](https://github.com/durch))
|
||||||
|
- Feature/remove unused profit margin [\#1011](https://github.com/nymtech/nym/pull/1011) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Feature/explorer node status [\#1010](https://github.com/nymtech/nym/pull/1010) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Use serial integer instead of random [\#1009](https://github.com/nymtech/nym/pull/1009) ([durch](https://github.com/durch))
|
||||||
|
- Feature/configure profit [\#1008](https://github.com/nymtech/nym/pull/1008) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Feature/fix gateway sign [\#1004](https://github.com/nymtech/nym/pull/1004) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Fix clippy [\#1003](https://github.com/nymtech/nym/pull/1003) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Update wallet version [\#998](https://github.com/nymtech/nym/pull/998) ([tommyv1987](https://github.com/tommyv1987))
|
||||||
|
- Fix wallet build instructions [\#997](https://github.com/nymtech/nym/pull/997) ([tommyv1987](https://github.com/tommyv1987))
|
||||||
|
- Make the separation between testnet-mode and erc20 bandwidth mode clearer [\#994](https://github.com/nymtech/nym/pull/994) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Bump @openzeppelin/contracts from 3.4.0 to 4.4.1 in /contracts/basic-bandwidth-generation [\#983](https://github.com/nymtech/nym/pull/983) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/implicit runtime [\#973](https://github.com/nymtech/nym/pull/973) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Differentiate staking and ownership [\#961](https://github.com/nymtech/nym/pull/961) ([durch](https://github.com/durch))
|
||||||
|
|
||||||
## [v0.12.1](https://github.com/nymtech/nym/tree/v0.12.1) (2021-12-23)
|
## [v0.12.1](https://github.com/nymtech/nym/tree/v0.12.1) (2021-12-23)
|
||||||
|
|
||||||
|
|||||||
Generated
+285
-694
File diff suppressed because it is too large
Load Diff
+8
-14
@@ -22,25 +22,22 @@ members = [
|
|||||||
"clients/native",
|
"clients/native",
|
||||||
"clients/native/websocket-requests",
|
"clients/native/websocket-requests",
|
||||||
"clients/socks5",
|
"clients/socks5",
|
||||||
"common/bandwidth-claim-contract",
|
|
||||||
"common/client-libs/gateway-client",
|
"common/client-libs/gateway-client",
|
||||||
"common/client-libs/mixnet-client",
|
"common/client-libs/mixnet-client",
|
||||||
"common/client-libs/validator-client",
|
"common/client-libs/validator-client",
|
||||||
|
"common/credential-storage",
|
||||||
"common/coconut-interface",
|
"common/coconut-interface",
|
||||||
"common/commands",
|
|
||||||
"common/config",
|
"common/config",
|
||||||
|
"common/credentials",
|
||||||
|
"common/crypto",
|
||||||
|
"common/crypto/dkg",
|
||||||
|
"common/execute",
|
||||||
|
"common/bandwidth-claim-contract",
|
||||||
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
||||||
"common/cosmwasm-smart-contracts/contracts-common",
|
"common/cosmwasm-smart-contracts/contracts-common",
|
||||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||||
"common/credential-storage",
|
|
||||||
"common/credentials",
|
|
||||||
"common/crypto",
|
|
||||||
"common/crypto/dkg",
|
|
||||||
"common/execute",
|
|
||||||
"common/inclusion-probability",
|
|
||||||
"common/ledger",
|
|
||||||
"common/mixnode-common",
|
"common/mixnode-common",
|
||||||
"common/network-defaults",
|
"common/network-defaults",
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
@@ -56,14 +53,13 @@ members = [
|
|||||||
"common/nymsphinx/params",
|
"common/nymsphinx/params",
|
||||||
"common/nymsphinx/types",
|
"common/nymsphinx/types",
|
||||||
"common/pemstore",
|
"common/pemstore",
|
||||||
|
"common/statistics",
|
||||||
"common/socks5/proxy-helpers",
|
"common/socks5/proxy-helpers",
|
||||||
"common/socks5/requests",
|
"common/socks5/requests",
|
||||||
"common/statistics",
|
|
||||||
"common/task",
|
"common/task",
|
||||||
"common/topology",
|
"common/topology",
|
||||||
"common/types",
|
"common/types",
|
||||||
"common/wasm-utils",
|
"common/wasm-utils",
|
||||||
"common/completions",
|
|
||||||
"explorer-api",
|
"explorer-api",
|
||||||
"gateway",
|
"gateway",
|
||||||
"gateway/gateway-requests",
|
"gateway/gateway-requests",
|
||||||
@@ -72,7 +68,6 @@ members = [
|
|||||||
"service-providers/network-statistics",
|
"service-providers/network-statistics",
|
||||||
"validator-api",
|
"validator-api",
|
||||||
"validator-api/validator-api-requests",
|
"validator-api/validator-api-requests",
|
||||||
"tools/nym-cli",
|
|
||||||
"tools/ts-rs-cli"
|
"tools/ts-rs-cli"
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -81,10 +76,9 @@ default-members = [
|
|||||||
"clients/socks5",
|
"clients/socks5",
|
||||||
"gateway",
|
"gateway",
|
||||||
"service-providers/network-requester",
|
"service-providers/network-requester",
|
||||||
"service-providers/network-statistics",
|
|
||||||
"mixnode",
|
"mixnode",
|
||||||
"validator-api",
|
"validator-api",
|
||||||
"explorer-api",
|
"explorer-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect"]
|
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly", "nym-wallet", "nym-connect"]
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
test: clippy-all cargo-test wasm fmt
|
|
||||||
test-all: test cargo-test-expensive
|
test-all: test cargo-test-expensive
|
||||||
|
test: build clippy-all cargo-test wasm fmt
|
||||||
no-clippy: build cargo-test wasm fmt
|
no-clippy: build cargo-test wasm fmt
|
||||||
happy: fmt clippy-happy test
|
happy: fmt clippy-happy test
|
||||||
clippy-all: clippy-main clippy-coconut clippy-all-contracts clippy-all-wallet clippy-all-connect
|
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
|
||||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
||||||
cargo-test: test-main test-contracts test-wallet test-connect test-coconut
|
cargo-test: test-main test-contracts test-wallet test-connect
|
||||||
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive test-coconut-expensive
|
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
|
||||||
build: build-contracts build-wallet build-main build-connect
|
build: build-contracts build-wallet build-main build-connect
|
||||||
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect
|
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect
|
||||||
|
|
||||||
@@ -21,15 +21,8 @@ clippy-happy-wallet:
|
|||||||
clippy-happy-connect:
|
clippy-happy-connect:
|
||||||
cargo clippy --manifest-path nym-connect/Cargo.toml
|
cargo clippy --manifest-path nym-connect/Cargo.toml
|
||||||
|
|
||||||
clippy-main:
|
clippy-all-main:
|
||||||
cargo clippy --workspace -- -D warnings
|
cargo clippy --workspace --all-features -- -D warnings
|
||||||
|
|
||||||
clippy-coconut:
|
|
||||||
cargo clippy --workspace --features coconut -- -D warnings
|
|
||||||
|
|
||||||
clippy-wasm:
|
|
||||||
cargo clippy --workspace --features wasm -- -D warnings
|
|
||||||
|
|
||||||
|
|
||||||
clippy-all-contracts:
|
clippy-all-contracts:
|
||||||
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||||
@@ -41,20 +34,10 @@ clippy-all-connect:
|
|||||||
cargo clippy --workspace --manifest-path nym-connect/Cargo.toml --all-features -- -D warnings
|
cargo clippy --workspace --manifest-path nym-connect/Cargo.toml --all-features -- -D warnings
|
||||||
|
|
||||||
test-main:
|
test-main:
|
||||||
cargo test --workspace
|
cargo test --all-features --workspace
|
||||||
|
|
||||||
test-coconut:
|
|
||||||
cargo test --workspace --features coconut
|
|
||||||
|
|
||||||
test-wasm:
|
|
||||||
cargo test --workspace --features wasm
|
|
||||||
|
|
||||||
|
|
||||||
test-main-expensive:
|
test-main-expensive:
|
||||||
cargo test --workspace -- --ignored
|
cargo test --all-features --workspace -- --ignored
|
||||||
|
|
||||||
test-coconut-expensive:
|
|
||||||
cargo test --workspace --features coconut -- --ignored
|
|
||||||
|
|
||||||
test-contracts:
|
test-contracts:
|
||||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||||
@@ -86,9 +69,6 @@ build-wallet:
|
|||||||
build-connect:
|
build-connect:
|
||||||
cargo build --manifest-path nym-connect/Cargo.toml --workspace
|
cargo build --manifest-path nym-connect/Cargo.toml --workspace
|
||||||
|
|
||||||
build-nym-cli:
|
|
||||||
cargo build --release --manifest-path tools/nym-cli/Cargo.toml
|
|
||||||
|
|
||||||
fmt-main:
|
fmt-main:
|
||||||
cargo fmt --all
|
cargo fmt --all
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ log = "0.4"
|
|||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
sled = "0.34"
|
sled = "0.34"
|
||||||
thiserror = "1.0.34"
|
|
||||||
tokio = { version = "1.19.1", features = ["macros"] }
|
tokio = { version = "1.19.1", features = ["macros"] }
|
||||||
url = { version ="2.2", features = ["serde"] }
|
url = { version ="2.2", features = ["serde"] }
|
||||||
|
|
||||||
@@ -26,10 +25,8 @@ gateway-requests = { path = "../../gateway/gateway-requests" }
|
|||||||
nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nymsphinx = { path = "../../common/nymsphinx" }
|
||||||
pemstore = { path = "../../common/pemstore" }
|
pemstore = { path = "../../common/pemstore" }
|
||||||
task = { path = "../../common/task" }
|
|
||||||
topology = { path = "../../common/topology" }
|
topology = { path = "../../common/topology" }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||||
tap = "1.0.1"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ use nymsphinx::utils::sample_poisson_duration;
|
|||||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
@@ -49,9 +48,6 @@ where
|
|||||||
|
|
||||||
/// Accessor to the common instance of network topology.
|
/// Accessor to the common instance of network topology.
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
|
|
||||||
/// Listen to shutdown signals.
|
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> Stream for LoopCoverTrafficStream<R>
|
impl<R> Stream for LoopCoverTrafficStream<R>
|
||||||
@@ -88,7 +84,6 @@ where
|
|||||||
// obviously when we finally make shared rng that is on 'higher' level, this should become
|
// obviously when we finally make shared rng that is on 'higher' level, this should become
|
||||||
// generic `R`
|
// generic `R`
|
||||||
impl LoopCoverTrafficStream<OsRng> {
|
impl LoopCoverTrafficStream<OsRng> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
average_ack_delay: time::Duration,
|
average_ack_delay: time::Duration,
|
||||||
@@ -97,7 +92,6 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
mix_tx: BatchMixMessageSender,
|
mix_tx: BatchMixMessageSender,
|
||||||
our_full_destination: Recipient,
|
our_full_destination: Recipient,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let rng = OsRng;
|
let rng = OsRng;
|
||||||
|
|
||||||
@@ -111,7 +105,6 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
our_full_destination,
|
our_full_destination,
|
||||||
rng,
|
rng,
|
||||||
topology_access,
|
topology_access,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +129,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
let cover_message = generate_loop_cover_packet(
|
let cover_message = generate_loop_cover_packet(
|
||||||
&mut self.rng,
|
&mut self.rng,
|
||||||
topology_ref,
|
topology_ref,
|
||||||
&self.ack_key,
|
&*self.ack_key,
|
||||||
&self.our_full_destination,
|
&self.our_full_destination,
|
||||||
self.average_ack_delay,
|
self.average_ack_delay,
|
||||||
self.average_packet_delay,
|
self.average_packet_delay,
|
||||||
@@ -166,25 +159,9 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
self.average_cover_message_sending_delay,
|
self.average_cover_message_sending_delay,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let mut shutdown = self.shutdown.clone();
|
while self.next().await.is_some() {
|
||||||
while !shutdown.is_shutdown() {
|
self.on_new_message().await;
|
||||||
tokio::select! {
|
|
||||||
biased;
|
|
||||||
_ = shutdown.recv() => {
|
|
||||||
log::trace!("LoopCoverTrafficStream: Received shutdown");
|
|
||||||
}
|
|
||||||
next = self.next() => {
|
|
||||||
if next.is_some() {
|
|
||||||
self.on_new_message().await;
|
|
||||||
} else {
|
|
||||||
log::trace!("LoopCoverTrafficStream: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
|
||||||
log::debug!("LoopCoverTrafficStream: Exiting");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(mut self) -> JoinHandle<()> {
|
pub fn start(mut self) -> JoinHandle<()> {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use futures::StreamExt;
|
|||||||
use gateway_client::GatewayClient;
|
use gateway_client::GatewayClient;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::forwarding::packet::MixPacket;
|
use nymsphinx::forwarding::packet::MixPacket;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>;
|
pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>;
|
||||||
@@ -19,7 +18,6 @@ pub struct MixTrafficController {
|
|||||||
// later on gateway_client will need to be accessible by other entities
|
// later on gateway_client will need to be accessible by other entities
|
||||||
gateway_client: GatewayClient,
|
gateway_client: GatewayClient,
|
||||||
mix_rx: BatchMixMessageReceiver,
|
mix_rx: BatchMixMessageReceiver,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
|
|
||||||
// TODO: this is temporary work-around.
|
// TODO: this is temporary work-around.
|
||||||
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
||||||
@@ -30,12 +28,10 @@ impl MixTrafficController {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
mix_rx: BatchMixMessageReceiver,
|
mix_rx: BatchMixMessageReceiver,
|
||||||
gateway_client: GatewayClient,
|
gateway_client: GatewayClient,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> MixTrafficController {
|
) -> MixTrafficController {
|
||||||
MixTrafficController {
|
MixTrafficController {
|
||||||
gateway_client,
|
gateway_client,
|
||||||
mix_rx,
|
mix_rx,
|
||||||
shutdown,
|
|
||||||
consecutive_gateway_failure_count: 0,
|
consecutive_gateway_failure_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,24 +66,9 @@ impl MixTrafficController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) {
|
pub async fn run(&mut self) {
|
||||||
while !self.shutdown.is_shutdown() {
|
while let Some(mix_packets) = self.mix_rx.next().await {
|
||||||
tokio::select! {
|
self.on_messages(mix_packets).await;
|
||||||
mix_packets = self.mix_rx.next() => match mix_packets {
|
|
||||||
Some(mix_packets) => {
|
|
||||||
self.on_messages(mix_packets).await;
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
log::trace!("MixTrafficController: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("MixTrafficController: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
|
||||||
log::debug!("MixTrafficController: Exiting");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(mut self) -> JoinHandle<()> {
|
pub fn start(mut self) -> JoinHandle<()> {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
|
|
||||||
pub mod cover_traffic_stream;
|
pub mod cover_traffic_stream;
|
||||||
pub mod inbound_messages;
|
pub mod inbound_messages;
|
||||||
pub mod key_manager;
|
pub mod key_manager;
|
||||||
@@ -8,10 +6,3 @@ pub mod real_messages_control;
|
|||||||
pub mod received_buffer;
|
pub mod received_buffer;
|
||||||
pub mod reply_key_storage;
|
pub mod reply_key_storage;
|
||||||
pub mod topology_control;
|
pub mod topology_control;
|
||||||
|
|
||||||
// This is *NOT* used to signal shutdown.
|
|
||||||
// It's critical that we don't have any tasks finishing early, this is an additional safety check
|
|
||||||
// that tasks exiting are doing so because shutdown has been signalled, and no other reason.
|
|
||||||
// In particular for tasks that rely on their associated channel being closed to signal shutdown,
|
|
||||||
// and don't have access to a shutdown listener channel.
|
|
||||||
pub static SHUTDOWN_HAS_BEEN_SIGNALLED: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|||||||
+5
-23
@@ -10,7 +10,6 @@ use nymsphinx::{
|
|||||||
chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID},
|
chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID},
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
/// Module responsible for listening for any data resembling acknowledgements from the network
|
/// Module responsible for listening for any data resembling acknowledgements from the network
|
||||||
/// and firing actions to remove them from the 'Pending' state.
|
/// and firing actions to remove them from the 'Pending' state.
|
||||||
@@ -18,7 +17,6 @@ pub(super) struct AcknowledgementListener {
|
|||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
ack_receiver: AcknowledgementReceiver,
|
ack_receiver: AcknowledgementReceiver,
|
||||||
action_sender: ActionSender,
|
action_sender: ActionSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AcknowledgementListener {
|
impl AcknowledgementListener {
|
||||||
@@ -26,13 +24,11 @@ impl AcknowledgementListener {
|
|||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
ack_receiver: AcknowledgementReceiver,
|
ack_receiver: AcknowledgementReceiver,
|
||||||
action_sender: ActionSender,
|
action_sender: ActionSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
AcknowledgementListener {
|
AcknowledgementListener {
|
||||||
ack_key,
|
ack_key,
|
||||||
ack_receiver,
|
ack_receiver,
|
||||||
action_sender,
|
action_sender,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,26 +65,12 @@ impl AcknowledgementListener {
|
|||||||
|
|
||||||
pub(super) async fn run(&mut self) {
|
pub(super) async fn run(&mut self) {
|
||||||
debug!("Started AcknowledgementListener");
|
debug!("Started AcknowledgementListener");
|
||||||
while !self.shutdown.is_shutdown() {
|
while let Some(acks) = self.ack_receiver.next().await {
|
||||||
tokio::select! {
|
// realistically we would only be getting one ack at the time
|
||||||
acks = self.ack_receiver.next() => match acks {
|
for ack in acks {
|
||||||
Some(acks) => {
|
self.on_ack(ack).await;
|
||||||
// realistically we would only be getting one ack at the time
|
|
||||||
for ack in acks {
|
|
||||||
self.on_ack(ack).await;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
log::trace!("AcknowledgementListener: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("AcknowledgementListener: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
error!("TODO: error msg. Or maybe panic?")
|
||||||
log::debug!("AcknowledgementListener: Exiting");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-28
@@ -12,7 +12,6 @@ use nymsphinx::Delay as SphinxDelay;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
pub(crate) type ActionSender = UnboundedSender<Action>;
|
pub(crate) type ActionSender = UnboundedSender<Action>;
|
||||||
|
|
||||||
@@ -100,16 +99,12 @@ pub(super) struct ActionController {
|
|||||||
|
|
||||||
/// Channel for notifying `RetransmissionRequestListener` about expired acknowledgements.
|
/// Channel for notifying `RetransmissionRequestListener` about expired acknowledgements.
|
||||||
retransmission_sender: RetransmissionRequestSender,
|
retransmission_sender: RetransmissionRequestSender,
|
||||||
|
|
||||||
/// Listen for shutdown notifications
|
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionController {
|
impl ActionController {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
config: Config,
|
config: Config,
|
||||||
retransmission_sender: RetransmissionRequestSender,
|
retransmission_sender: RetransmissionRequestSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> (Self, ActionSender) {
|
) -> (Self, ActionSender) {
|
||||||
let (sender, receiver) = mpsc::unbounded();
|
let (sender, receiver) = mpsc::unbounded();
|
||||||
(
|
(
|
||||||
@@ -119,7 +114,6 @@ impl ActionController {
|
|||||||
pending_acks_timers: NonExhaustiveDelayQueue::new(),
|
pending_acks_timers: NonExhaustiveDelayQueue::new(),
|
||||||
incoming_actions: receiver,
|
incoming_actions: receiver,
|
||||||
retransmission_sender,
|
retransmission_sender,
|
||||||
shutdown,
|
|
||||||
},
|
},
|
||||||
sender,
|
sender,
|
||||||
)
|
)
|
||||||
@@ -252,30 +246,14 @@ impl ActionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn run(&mut self) {
|
pub(super) async fn run(&mut self) {
|
||||||
while !self.shutdown.is_shutdown() {
|
loop {
|
||||||
|
// at some point there will be a global shutdown signal here as the third option
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
action = self.incoming_actions.next() => match action {
|
// we NEVER expect for ANY sender to get dropped so unwrap here is fine
|
||||||
Some(action) => self.process_action(action),
|
action = self.incoming_actions.next() => self.process_action(action.unwrap()),
|
||||||
None => {
|
// pending ack queue Stream CANNOT return a `None` so unwrap here is fine
|
||||||
log::trace!(
|
expired_ack = self.pending_acks_timers.next() => self.handle_expired_ack_timer(expired_ack.unwrap())
|
||||||
"ActionController: Stopping since incoming actions channel closed"
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
expired_ack = self.pending_acks_timers.next() => match expired_ack {
|
|
||||||
Some(expired_ack) => self.handle_expired_ack_timer(expired_ack),
|
|
||||||
None => {
|
|
||||||
log::trace!("ActionController: Stopping since ack channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("ActionController: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
|
||||||
log::debug!("ActionController: Exiting");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-21
@@ -16,7 +16,6 @@ use nymsphinx::preparer::MessagePreparer;
|
|||||||
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
/// Module responsible for dealing with the received messages: splitting them, creating acknowledgements,
|
/// Module responsible for dealing with the received messages: splitting them, creating acknowledgements,
|
||||||
/// putting everything into sphinx packets, etc.
|
/// putting everything into sphinx packets, etc.
|
||||||
@@ -33,7 +32,6 @@ where
|
|||||||
real_message_sender: BatchRealMessageSender,
|
real_message_sender: BatchRealMessageSender,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> InputMessageListener<R>
|
impl<R> InputMessageListener<R>
|
||||||
@@ -52,7 +50,6 @@ where
|
|||||||
real_message_sender: BatchRealMessageSender,
|
real_message_sender: BatchRealMessageSender,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
InputMessageListener {
|
InputMessageListener {
|
||||||
ack_key,
|
ack_key,
|
||||||
@@ -63,7 +60,6 @@ where
|
|||||||
real_message_sender,
|
real_message_sender,
|
||||||
topology_access,
|
topology_access,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +133,7 @@ where
|
|||||||
let prepared_fragment = self
|
let prepared_fragment = self
|
||||||
.message_preparer
|
.message_preparer
|
||||||
.prepare_chunk_for_sending(chunk_clone, topology, &self.ack_key, &recipient)
|
.prepare_chunk_for_sending(chunk_clone, topology, &self.ack_key, &recipient)
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
real_messages.push(RealMessage::new(
|
real_messages.push(RealMessage::new(
|
||||||
@@ -186,23 +183,9 @@ where
|
|||||||
|
|
||||||
pub(super) async fn run(&mut self) {
|
pub(super) async fn run(&mut self) {
|
||||||
debug!("Started InputMessageListener");
|
debug!("Started InputMessageListener");
|
||||||
while !self.shutdown.is_shutdown() {
|
while let Some(input_msg) = self.input_receiver.next().await {
|
||||||
tokio::select! {
|
self.on_input_message(input_msg).await;
|
||||||
input_msg = self.input_receiver.next() => match input_msg {
|
|
||||||
Some(input_msg) => {
|
|
||||||
self.on_input_message(input_msg).await;
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
log::trace!("InputMessageListener: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("InputMessageListener: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
error!("TODO: error msg. Or maybe panic?")
|
||||||
log::debug!("InputMessageListener: Exiting");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-13
@@ -25,7 +25,6 @@ use std::{
|
|||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
mod acknowledgement_listener;
|
mod acknowledgement_listener;
|
||||||
@@ -153,7 +152,6 @@ impl<R> AcknowledgementController<R>
|
|||||||
where
|
where
|
||||||
R: 'static + CryptoRng + Rng + Clone + Send,
|
R: 'static + CryptoRng + Rng + Clone + Send,
|
||||||
{
|
{
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
config: Config,
|
config: Config,
|
||||||
rng: R,
|
rng: R,
|
||||||
@@ -162,14 +160,13 @@ where
|
|||||||
ack_recipient: Recipient,
|
ack_recipient: Recipient,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
connectors: AcknowledgementControllerConnectors,
|
connectors: AcknowledgementControllerConnectors,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (retransmission_tx, retransmission_rx) = mpsc::unbounded();
|
let (retransmission_tx, retransmission_rx) = mpsc::unbounded();
|
||||||
|
|
||||||
let action_config =
|
let action_config =
|
||||||
action_controller::Config::new(config.ack_wait_addition, config.ack_wait_multiplier);
|
action_controller::Config::new(config.ack_wait_addition, config.ack_wait_multiplier);
|
||||||
let (action_controller, action_sender) =
|
let (action_controller, action_sender) =
|
||||||
ActionController::new(action_config, retransmission_tx, shutdown.clone());
|
ActionController::new(action_config, retransmission_tx);
|
||||||
|
|
||||||
let message_preparer = MessagePreparer::new(
|
let message_preparer = MessagePreparer::new(
|
||||||
rng,
|
rng,
|
||||||
@@ -183,7 +180,6 @@ where
|
|||||||
Arc::clone(&ack_key),
|
Arc::clone(&ack_key),
|
||||||
connectors.ack_receiver,
|
connectors.ack_receiver,
|
||||||
action_sender.clone(),
|
action_sender.clone(),
|
||||||
shutdown.clone(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// will listen for any new messages from the client
|
// will listen for any new messages from the client
|
||||||
@@ -196,7 +192,6 @@ where
|
|||||||
connectors.real_message_sender.clone(),
|
connectors.real_message_sender.clone(),
|
||||||
topology_access.clone(),
|
topology_access.clone(),
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
shutdown.clone(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// will listen for any ack timeouts and trigger retransmission
|
// will listen for any ack timeouts and trigger retransmission
|
||||||
@@ -208,13 +203,12 @@ where
|
|||||||
connectors.real_message_sender,
|
connectors.real_message_sender,
|
||||||
retransmission_rx,
|
retransmission_rx,
|
||||||
topology_access,
|
topology_access,
|
||||||
shutdown.clone(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// will listen for events indicating the packet was sent through the network so that
|
// will listen for events indicating the packet was sent through the network so that
|
||||||
// the retransmission timer should be started.
|
// the retransmission timer should be started.
|
||||||
let sent_notification_listener =
|
let sent_notification_listener =
|
||||||
SentNotificationListener::new(connectors.sent_notifier, action_sender, shutdown);
|
SentNotificationListener::new(connectors.sent_notifier, action_sender);
|
||||||
|
|
||||||
AcknowledgementController {
|
AcknowledgementController {
|
||||||
acknowledgement_listener: Some(acknowledgement_listener),
|
acknowledgement_listener: Some(acknowledgement_listener),
|
||||||
@@ -238,27 +232,27 @@ where
|
|||||||
// graceful shutdowns.
|
// graceful shutdowns.
|
||||||
let ack_listener_fut = tokio::spawn(async move {
|
let ack_listener_fut = tokio::spawn(async move {
|
||||||
acknowledgement_listener.run().await;
|
acknowledgement_listener.run().await;
|
||||||
debug!("The acknowledgement listener has finished execution!");
|
error!("The acknowledgement listener has finished execution!");
|
||||||
acknowledgement_listener
|
acknowledgement_listener
|
||||||
});
|
});
|
||||||
let input_listener_fut = tokio::spawn(async move {
|
let input_listener_fut = tokio::spawn(async move {
|
||||||
input_message_listener.run().await;
|
input_message_listener.run().await;
|
||||||
debug!("The input listener has finished execution!");
|
error!("The input listener has finished execution!");
|
||||||
input_message_listener
|
input_message_listener
|
||||||
});
|
});
|
||||||
let retransmission_req_fut = tokio::spawn(async move {
|
let retransmission_req_fut = tokio::spawn(async move {
|
||||||
retransmission_request_listener.run().await;
|
retransmission_request_listener.run().await;
|
||||||
debug!("The retransmission request listener has finished execution!");
|
error!("The retransmission request listener has finished execution!");
|
||||||
retransmission_request_listener
|
retransmission_request_listener
|
||||||
});
|
});
|
||||||
let sent_notification_fut = tokio::spawn(async move {
|
let sent_notification_fut = tokio::spawn(async move {
|
||||||
sent_notification_listener.run().await;
|
sent_notification_listener.run().await;
|
||||||
debug!("The sent notification listener has finished execution!");
|
error!("The sent notification listener has finished execution!");
|
||||||
sent_notification_listener
|
sent_notification_listener
|
||||||
});
|
});
|
||||||
let action_controller_fut = tokio::spawn(async move {
|
let action_controller_fut = tokio::spawn(async move {
|
||||||
action_controller.run().await;
|
action_controller.run().await;
|
||||||
debug!("The controller has finished execution!");
|
error!("The controller has finished execution!");
|
||||||
action_controller
|
action_controller
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+4
-21
@@ -14,7 +14,6 @@ use nymsphinx::preparer::MessagePreparer;
|
|||||||
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
// responsible for packet retransmission upon fired timer
|
// responsible for packet retransmission upon fired timer
|
||||||
pub(super) struct RetransmissionRequestListener<R>
|
pub(super) struct RetransmissionRequestListener<R>
|
||||||
@@ -28,14 +27,12 @@ where
|
|||||||
real_message_sender: BatchRealMessageSender,
|
real_message_sender: BatchRealMessageSender,
|
||||||
request_receiver: RetransmissionRequestReceiver,
|
request_receiver: RetransmissionRequestReceiver,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> RetransmissionRequestListener<R>
|
impl<R> RetransmissionRequestListener<R>
|
||||||
where
|
where
|
||||||
R: CryptoRng + Rng,
|
R: CryptoRng + Rng,
|
||||||
{
|
{
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
ack_recipient: Recipient,
|
ack_recipient: Recipient,
|
||||||
@@ -44,7 +41,6 @@ where
|
|||||||
real_message_sender: BatchRealMessageSender,
|
real_message_sender: BatchRealMessageSender,
|
||||||
request_receiver: RetransmissionRequestReceiver,
|
request_receiver: RetransmissionRequestReceiver,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
RetransmissionRequestListener {
|
RetransmissionRequestListener {
|
||||||
ack_key,
|
ack_key,
|
||||||
@@ -54,7 +50,6 @@ where
|
|||||||
real_message_sender,
|
real_message_sender,
|
||||||
request_receiver,
|
request_receiver,
|
||||||
topology_access,
|
topology_access,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +83,7 @@ where
|
|||||||
let prepared_fragment = self
|
let prepared_fragment = self
|
||||||
.message_preparer
|
.message_preparer
|
||||||
.prepare_chunk_for_sending(chunk_clone, topology_ref, &self.ack_key, packet_recipient)
|
.prepare_chunk_for_sending(chunk_clone, topology_ref, &self.ack_key, packet_recipient)
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// if we have the ONLY strong reference to the ack data, it means it was removed from the
|
// if we have the ONLY strong reference to the ack data, it means it was removed from the
|
||||||
@@ -126,22 +122,9 @@ where
|
|||||||
|
|
||||||
pub(super) async fn run(&mut self) {
|
pub(super) async fn run(&mut self) {
|
||||||
debug!("Started RetransmissionRequestListener");
|
debug!("Started RetransmissionRequestListener");
|
||||||
|
while let Some(timed_out_ack) = self.request_receiver.next().await {
|
||||||
while !self.shutdown.is_shutdown() {
|
self.on_retransmission_request(timed_out_ack).await;
|
||||||
tokio::select! {
|
|
||||||
timed_out_ack = self.request_receiver.next() => match timed_out_ack {
|
|
||||||
Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack).await,
|
|
||||||
None => {
|
|
||||||
log::trace!("RetransmissionRequestListener: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("RetransmissionRequestListener: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
error!("TODO: error msg. Or maybe panic?")
|
||||||
log::debug!("RetransmissionRequestListener: Exiting");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-21
@@ -6,7 +6,6 @@ use super::SentPacketNotificationReceiver;
|
|||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
|
use nymsphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
/// Module responsible for starting up retransmission timers.
|
/// Module responsible for starting up retransmission timers.
|
||||||
/// It is required because when we send our packet to the `real traffic stream` controlled
|
/// It is required because when we send our packet to the `real traffic stream` controlled
|
||||||
@@ -15,19 +14,16 @@ use task::ShutdownListener;
|
|||||||
pub(super) struct SentNotificationListener {
|
pub(super) struct SentNotificationListener {
|
||||||
sent_notifier: SentPacketNotificationReceiver,
|
sent_notifier: SentPacketNotificationReceiver,
|
||||||
action_sender: ActionSender,
|
action_sender: ActionSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SentNotificationListener {
|
impl SentNotificationListener {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
sent_notifier: SentPacketNotificationReceiver,
|
sent_notifier: SentPacketNotificationReceiver,
|
||||||
action_sender: ActionSender,
|
action_sender: ActionSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
SentNotificationListener {
|
SentNotificationListener {
|
||||||
sent_notifier,
|
sent_notifier,
|
||||||
action_sender,
|
action_sender,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,23 +44,9 @@ impl SentNotificationListener {
|
|||||||
|
|
||||||
pub(super) async fn run(&mut self) {
|
pub(super) async fn run(&mut self) {
|
||||||
debug!("Started SentNotificationListener");
|
debug!("Started SentNotificationListener");
|
||||||
while !self.shutdown.is_shutdown() {
|
while let Some(frag_id) = self.sent_notifier.next().await {
|
||||||
tokio::select! {
|
self.on_sent_message(frag_id).await;
|
||||||
frag_id = self.sent_notifier.next() => match frag_id {
|
|
||||||
Some(frag_id) => {
|
|
||||||
self.on_sent_message(frag_id).await;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::trace!("SentNotificationListener: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("SentNotificationListener: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
error!("TODO: error msg. Or maybe panic?")
|
||||||
log::debug!("SentNotificationListener: Exiting");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ use nymsphinx::addressing::clients::Recipient;
|
|||||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
mod acknowledgement_control;
|
mod acknowledgement_control;
|
||||||
@@ -92,7 +91,6 @@ impl RealMessagesController<OsRng> {
|
|||||||
mix_sender: BatchMixMessageSender,
|
mix_sender: BatchMixMessageSender,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let rng = OsRng;
|
let rng = OsRng;
|
||||||
|
|
||||||
@@ -121,7 +119,6 @@ impl RealMessagesController<OsRng> {
|
|||||||
config.self_recipient,
|
config.self_recipient,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
ack_controller_connectors,
|
ack_controller_connectors,
|
||||||
shutdown.clone(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let out_queue_config = real_traffic_stream::Config::new(
|
let out_queue_config = real_traffic_stream::Config::new(
|
||||||
@@ -139,7 +136,6 @@ impl RealMessagesController<OsRng> {
|
|||||||
rng,
|
rng,
|
||||||
config.self_recipient,
|
config.self_recipient,
|
||||||
topology_access,
|
topology_access,
|
||||||
shutdown,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
RealMessagesController {
|
RealMessagesController {
|
||||||
@@ -157,12 +153,12 @@ impl RealMessagesController<OsRng> {
|
|||||||
// graceful shutdowns.
|
// graceful shutdowns.
|
||||||
let out_queue_control_fut = tokio::spawn(async move {
|
let out_queue_control_fut = tokio::spawn(async move {
|
||||||
out_queue_control.run_out_queue_control().await;
|
out_queue_control.run_out_queue_control().await;
|
||||||
debug!("The out queue controller has finished execution!");
|
error!("The out queue controller has finished execution!");
|
||||||
out_queue_control
|
out_queue_control
|
||||||
});
|
});
|
||||||
let ack_control_fut = tokio::spawn(async move {
|
let ack_control_fut = tokio::spawn(async move {
|
||||||
ack_control.run().await;
|
ack_control.run().await;
|
||||||
debug!("The acknowledgement controller has finished execution!");
|
error!("The acknowledgement controller has finished execution!");
|
||||||
ack_control
|
ack_control
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use std::collections::VecDeque;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
/// Configurable parameters of the `OutQueueControl`
|
/// Configurable parameters of the `OutQueueControl`
|
||||||
@@ -84,9 +83,6 @@ where
|
|||||||
|
|
||||||
/// Buffer containing all real messages received. It is first exhausted before more are pulled.
|
/// Buffer containing all real messages received. It is first exhausted before more are pulled.
|
||||||
received_buffer: VecDeque<RealMessage>,
|
received_buffer: VecDeque<RealMessage>,
|
||||||
|
|
||||||
/// Listens for shutdown signals
|
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RealMessage {
|
pub(crate) struct RealMessage {
|
||||||
@@ -178,7 +174,6 @@ where
|
|||||||
rng: R,
|
rng: R,
|
||||||
our_full_destination: Recipient,
|
our_full_destination: Recipient,
|
||||||
topology_access: TopologyAccessor,
|
topology_access: TopologyAccessor,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
OutQueueControl {
|
OutQueueControl {
|
||||||
config,
|
config,
|
||||||
@@ -191,7 +186,6 @@ where
|
|||||||
rng,
|
rng,
|
||||||
topology_access,
|
topology_access,
|
||||||
received_buffer: VecDeque::with_capacity(0), // we won't be putting any data into this guy directly
|
received_buffer: VecDeque::with_capacity(0), // we won't be putting any data into this guy directly
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +222,7 @@ where
|
|||||||
generate_loop_cover_packet(
|
generate_loop_cover_packet(
|
||||||
&mut self.rng,
|
&mut self.rng,
|
||||||
topology_ref,
|
topology_ref,
|
||||||
&self.ack_key,
|
&*self.ack_key,
|
||||||
&self.our_full_destination,
|
&self.our_full_destination,
|
||||||
self.config.average_ack_delay,
|
self.config.average_ack_delay,
|
||||||
self.config.average_packet_delay,
|
self.config.average_packet_delay,
|
||||||
@@ -245,15 +239,7 @@ where
|
|||||||
// - we run out of memory
|
// - we run out of memory
|
||||||
// - the receiver channel is closed
|
// - the receiver channel is closed
|
||||||
// in either case there's no recovery and we can only panic
|
// in either case there's no recovery and we can only panic
|
||||||
if let Err(err) = self.mix_tx.unbounded_send(vec![next_message]) {
|
self.mix_tx.unbounded_send(vec![next_message]).unwrap();
|
||||||
if self.shutdown.is_shutdown_poll() {
|
|
||||||
log::info!("Failed to send (shutdown detected)");
|
|
||||||
} else {
|
|
||||||
// We don't try to limp along, panic to avoid continuing in a potentially
|
|
||||||
// inconsistent state
|
|
||||||
panic!("{err}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// JS: Not entirely sure why or how it fixes stuff, but without the yield call,
|
// JS: Not entirely sure why or how it fixes stuff, but without the yield call,
|
||||||
// the UnboundedReceiver [of mix_rx] will not get a chance to read anything
|
// the UnboundedReceiver [of mix_rx] will not get a chance to read anything
|
||||||
@@ -271,26 +257,9 @@ where
|
|||||||
self.config.average_message_sending_delay,
|
self.config.average_message_sending_delay,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let mut shutdown = self.shutdown.clone();
|
while let Some(next_message) = self.next().await {
|
||||||
while !shutdown.is_shutdown() {
|
self.on_message(next_message).await;
|
||||||
tokio::select! {
|
|
||||||
biased;
|
|
||||||
_ = shutdown.recv() => {
|
|
||||||
log::trace!("OutQueueControl: Received shutdown");
|
|
||||||
}
|
|
||||||
next_message = self.next() => match next_message {
|
|
||||||
Some(next_message) => {
|
|
||||||
self.on_message(next_message).await;
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
log::trace!("OutQueueControl: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(shutdown.is_shutdown_poll());
|
|
||||||
log::debug!("OutQueueControl: Exiting");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn run_out_queue_control(&mut self) {
|
pub(crate) async fn run_out_queue_control(&mut self) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::reply_key_storage::ReplyKeyStorage;
|
use crate::client::reply_key_storage::ReplyKeyStorage;
|
||||||
use crate::client::SHUTDOWN_HAS_BEEN_SIGNALLED;
|
|
||||||
use crypto::asymmetric::encryption;
|
use crypto::asymmetric::encryption;
|
||||||
use crypto::symmetric::stream_cipher;
|
use crypto::symmetric::stream_cipher;
|
||||||
use crypto::Digest;
|
use crypto::Digest;
|
||||||
@@ -15,9 +14,7 @@ use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncr
|
|||||||
use nymsphinx::params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
use nymsphinx::params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
||||||
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
// Buffer Requests to say "hey, send any reconstructed messages to this channel"
|
// Buffer Requests to say "hey, send any reconstructed messages to this channel"
|
||||||
@@ -295,27 +292,16 @@ impl RequestReceiver {
|
|||||||
|
|
||||||
fn start(mut self) -> JoinHandle<()> {
|
fn start(mut self) -> JoinHandle<()> {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
while let Some(request) = self.query_receiver.next().await {
|
||||||
tokio::select! {
|
match request {
|
||||||
request = self.query_receiver.next() => {
|
ReceivedBufferMessage::ReceiverAnnounce(sender) => {
|
||||||
match request {
|
self.received_buffer.connect_sender(sender).await;
|
||||||
Some(ReceivedBufferMessage::ReceiverAnnounce(sender)) => {
|
}
|
||||||
self.received_buffer.connect_sender(sender).await;
|
ReceivedBufferMessage::ReceiverDisconnect => {
|
||||||
}
|
self.received_buffer.disconnect_sender().await
|
||||||
Some(ReceivedBufferMessage::ReceiverDisconnect) => {
|
}
|
||||||
self.received_buffer.disconnect_sender().await
|
}
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::trace!("RequestReceiver: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(SHUTDOWN_HAS_BEEN_SIGNALLED.load(Ordering::Relaxed));
|
|
||||||
log::debug!("RequestReceiver: Exiting");
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,41 +309,23 @@ impl RequestReceiver {
|
|||||||
struct FragmentedMessageReceiver {
|
struct FragmentedMessageReceiver {
|
||||||
received_buffer: ReceivedMessagesBuffer,
|
received_buffer: ReceivedMessagesBuffer,
|
||||||
mixnet_packet_receiver: MixnetMessageReceiver,
|
mixnet_packet_receiver: MixnetMessageReceiver,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FragmentedMessageReceiver {
|
impl FragmentedMessageReceiver {
|
||||||
fn new(
|
fn new(
|
||||||
received_buffer: ReceivedMessagesBuffer,
|
received_buffer: ReceivedMessagesBuffer,
|
||||||
mixnet_packet_receiver: MixnetMessageReceiver,
|
mixnet_packet_receiver: MixnetMessageReceiver,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
FragmentedMessageReceiver {
|
FragmentedMessageReceiver {
|
||||||
received_buffer,
|
received_buffer,
|
||||||
mixnet_packet_receiver,
|
mixnet_packet_receiver,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn start(mut self) -> JoinHandle<()> {
|
fn start(mut self) -> JoinHandle<()> {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while !self.shutdown.is_shutdown() {
|
while let Some(new_messages) = self.mixnet_packet_receiver.next().await {
|
||||||
tokio::select! {
|
self.received_buffer.handle_new_received(new_messages).await;
|
||||||
new_messages = self.mixnet_packet_receiver.next() => match new_messages {
|
|
||||||
Some(new_messages) => {
|
|
||||||
self.received_buffer.handle_new_received(new_messages).await;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::trace!("FragmentedMessageReceiver: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("FragmentedMessageReceiver: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
|
||||||
log::debug!("FragmentedMessageReceiver: Exiting");
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,7 +341,6 @@ impl ReceivedMessagesBufferController {
|
|||||||
query_receiver: ReceivedBufferRequestReceiver,
|
query_receiver: ReceivedBufferRequestReceiver,
|
||||||
mixnet_packet_receiver: MixnetMessageReceiver,
|
mixnet_packet_receiver: MixnetMessageReceiver,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let received_buffer =
|
let received_buffer =
|
||||||
ReceivedMessagesBuffer::new(local_encryption_keypair, reply_key_storage);
|
ReceivedMessagesBuffer::new(local_encryption_keypair, reply_key_storage);
|
||||||
@@ -382,7 +349,6 @@ impl ReceivedMessagesBufferController {
|
|||||||
fragmented_message_receiver: FragmentedMessageReceiver::new(
|
fragmented_message_receiver: FragmentedMessageReceiver::new(
|
||||||
received_buffer.clone(),
|
received_buffer.clone(),
|
||||||
mixnet_packet_receiver,
|
mixnet_packet_receiver,
|
||||||
shutdown,
|
|
||||||
),
|
),
|
||||||
request_receiver: RequestReceiver::new(received_buffer, query_receiver),
|
request_receiver: RequestReceiver::new(received_buffer, query_receiver),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ use std::ops::Deref;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time;
|
use std::time;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use topology::{nym_topology_from_detailed, NymTopology};
|
use topology::{nym_topology_from_bonds, NymTopology};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
||||||
@@ -266,8 +265,8 @@ impl TopologyRefresher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mixnodes_count = mixnodes.len();
|
let mixnodes_count = mixnodes.len();
|
||||||
let topology = nym_topology_from_detailed(mixnodes, gateways)
|
let topology =
|
||||||
.filter_system_version(&self.client_version);
|
nym_topology_from_bonds(mixnodes, gateways).filter_system_version(&self.client_version);
|
||||||
|
|
||||||
if !self.check_layer_distribution(&topology, mixnodes_count) {
|
if !self.check_layer_distribution(&topology, mixnodes_count) {
|
||||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||||
@@ -304,20 +303,12 @@ impl TopologyRefresher {
|
|||||||
self.topology_accessor.is_routable().await
|
self.topology_accessor.is_routable().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(mut self, mut shutdown: ShutdownListener) -> JoinHandle<()> {
|
pub fn start(mut self) -> JoinHandle<()> {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while !shutdown.is_shutdown() {
|
loop {
|
||||||
tokio::select! {
|
tokio::time::sleep(self.refresh_rate).await;
|
||||||
_ = tokio::time::sleep(self.refresh_rate) => {
|
self.refresh().await;
|
||||||
self.refresh().await;
|
|
||||||
},
|
|
||||||
_ = shutdown.recv() => {
|
|
||||||
log::trace!("TopologyRefresher: Received shutdown");
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert!(shutdown.is_shutdown_poll());
|
|
||||||
log::debug!("TopologyRefresher: Exiting");
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use config::defaults::*;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@@ -121,6 +122,16 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.gateway_endpoint.gateway_id = id.into();
|
self.client.gateway_endpoint.gateway_id = id.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn with_eth_private_key<S: Into<String>>(&mut self, eth_private_key: S) {
|
||||||
|
self.client.eth_private_key = eth_private_key.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn with_eth_endpoint<S: Into<String>>(&mut self, eth_endpoint: S) {
|
||||||
|
self.client.eth_endpoint = eth_endpoint.into();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
|
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
|
||||||
self.client.validator_api_urls = validator_api_urls;
|
self.client.validator_api_urls = validator_api_urls;
|
||||||
}
|
}
|
||||||
@@ -199,6 +210,16 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.database_path.clone()
|
self.client.database_path.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn get_eth_endpoint(&self) -> String {
|
||||||
|
self.client.eth_endpoint.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn get_eth_private_key(&self) -> String {
|
||||||
|
self.client.eth_private_key.clone()
|
||||||
|
}
|
||||||
|
|
||||||
// Debug getters
|
// Debug getters
|
||||||
pub fn get_average_packet_delay(&self) -> Duration {
|
pub fn get_average_packet_delay(&self) -> Duration {
|
||||||
self.debug.average_packet_delay
|
self.debug.average_packet_delay
|
||||||
@@ -322,6 +343,14 @@ pub struct Client<T> {
|
|||||||
/// Path to the database containing bandwidth credentials of this client.
|
/// Path to the database containing bandwidth credentials of this client.
|
||||||
database_path: PathBuf,
|
database_path: PathBuf,
|
||||||
|
|
||||||
|
/// Ethereum private key.
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_private_key: String,
|
||||||
|
|
||||||
|
/// Address to an Ethereum full node.
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_endpoint: String,
|
||||||
|
|
||||||
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
||||||
/// It is expected to use default value and hence .toml file should not redefine this field.
|
/// It is expected to use default value and hence .toml file should not redefine this field.
|
||||||
nym_root_directory: PathBuf,
|
nym_root_directory: PathBuf,
|
||||||
@@ -337,7 +366,7 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||||
id: "".to_string(),
|
id: "".to_string(),
|
||||||
disabled_credentials_mode: true,
|
disabled_credentials_mode: true,
|
||||||
validator_api_urls: vec![],
|
validator_api_urls: default_api_endpoints(),
|
||||||
private_identity_key_file: Default::default(),
|
private_identity_key_file: Default::default(),
|
||||||
public_identity_key_file: Default::default(),
|
public_identity_key_file: Default::default(),
|
||||||
private_encryption_key_file: Default::default(),
|
private_encryption_key_file: Default::default(),
|
||||||
@@ -347,6 +376,10 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
reply_encryption_key_store_path: Default::default(),
|
reply_encryption_key_store_path: Default::default(),
|
||||||
gateway_endpoint: Default::default(),
|
gateway_endpoint: Default::default(),
|
||||||
database_path: Default::default(),
|
database_path: Default::default(),
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_private_key: "".to_string(),
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_endpoint: "".to_string(),
|
||||||
nym_root_directory: T::default_root_directory(),
|
nym_root_directory: T::default_root_directory(),
|
||||||
super_struct: Default::default(),
|
super_struct: Default::default(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crypto::asymmetric::identity::Ed25519RecoveryError;
|
|
||||||
use gateway_client::error::GatewayClientError;
|
|
||||||
use validator_client::ValidatorClientError;
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum ClientCoreError {
|
|
||||||
#[error("I/O error: {0}")]
|
|
||||||
IoError(#[from] std::io::Error),
|
|
||||||
#[error("Gateway client error: {0}")]
|
|
||||||
GatewayClientError(#[from] GatewayClientError),
|
|
||||||
#[error("Ed25519 error: {0}")]
|
|
||||||
Ed25519RecoveryError(#[from] Ed25519RecoveryError),
|
|
||||||
#[error("Validator client error: {0}")]
|
|
||||||
ValidatorClientError(#[from] ValidatorClientError),
|
|
||||||
|
|
||||||
#[error("No gateway with id: {0}")]
|
|
||||||
NoGatewayWithId(String),
|
|
||||||
#[error("No gateways on network")]
|
|
||||||
NoGatewaysOnNetwork,
|
|
||||||
#[error("List of validator apis is empty")]
|
|
||||||
ListOfValidatorApisIsEmpty,
|
|
||||||
#[error("Could not load existing gateway configuration: {0}")]
|
|
||||||
CouldNotLoadExistingGatewayConfiguration(std::io::Error),
|
|
||||||
}
|
|
||||||
@@ -14,27 +14,25 @@ use nymsphinx::addressing::nodes::NodeIdentity;
|
|||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use tap::TapFallible;
|
|
||||||
use topology::{filter::VersionFilterable, gateway};
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::key_manager::KeyManager,
|
client::key_manager::KeyManager,
|
||||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
||||||
error::ClientCoreError,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn query_gateway_details(
|
pub async fn query_gateway_details(
|
||||||
validator_servers: Vec<Url>,
|
validator_servers: Vec<Url>,
|
||||||
chosen_gateway_id: Option<&str>,
|
chosen_gateway_id: Option<&str>,
|
||||||
) -> Result<gateway::Node, ClientCoreError> {
|
) -> gateway::Node {
|
||||||
let validator_api = validator_servers
|
let validator_api = validator_servers
|
||||||
.choose(&mut thread_rng())
|
.choose(&mut thread_rng())
|
||||||
.ok_or(ClientCoreError::ListOfValidatorApisIsEmpty)?;
|
.expect("The list of validator apis is empty");
|
||||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||||
|
|
||||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||||
let gateways = validator_client.get_cached_gateways().await?;
|
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||||
let valid_gateways = gateways
|
let valid_gateways = gateways
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|gateway| gateway.try_into().ok())
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
@@ -49,40 +47,38 @@ pub async fn query_gateway_details(
|
|||||||
filtered_gateways
|
filtered_gateways
|
||||||
.iter()
|
.iter()
|
||||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_id.to_string()))
|
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||||
.cloned()
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
filtered_gateways
|
filtered_gateways
|
||||||
.choose(&mut rand::thread_rng())
|
.choose(&mut rand::thread_rng())
|
||||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
.expect("there are no gateways on the network!")
|
||||||
.cloned()
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register_with_gateway_and_store_keys<T>(
|
pub async fn register_with_gateway_and_store_keys<T>(
|
||||||
gateway_details: gateway::Node,
|
gateway_details: gateway::Node,
|
||||||
config: &Config<T>,
|
config: &Config<T>,
|
||||||
) -> Result<(), ClientCoreError>
|
) where
|
||||||
where
|
|
||||||
T: NymConfig,
|
T: NymConfig,
|
||||||
{
|
{
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let mut key_manager = KeyManager::new(&mut rng);
|
let mut key_manager = KeyManager::new(&mut rng);
|
||||||
|
|
||||||
let shared_keys =
|
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||||
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await?;
|
|
||||||
key_manager.insert_gateway_shared_key(shared_keys);
|
key_manager.insert_gateway_shared_key(shared_keys);
|
||||||
|
|
||||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||||
Ok(key_manager
|
key_manager
|
||||||
.store_keys(&pathfinder)
|
.store_keys(&pathfinder)
|
||||||
.tap_err(|err| log::error!("Failed to generate keys: {err}"))?)
|
.expect("Failed to generated keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_with_gateway(
|
async fn register_with_gateway(
|
||||||
gateway: &gateway::Node,
|
gateway: &gateway::Node,
|
||||||
our_identity: Arc<identity::KeyPair>,
|
our_identity: Arc<identity::KeyPair>,
|
||||||
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
) -> Arc<SharedKeys> {
|
||||||
let timeout = Duration::from_millis(1500);
|
let timeout = Duration::from_millis(1500);
|
||||||
let mut gateway_client = GatewayClient::new_init(
|
let mut gateway_client = GatewayClient::new_init(
|
||||||
gateway.clients_address(),
|
gateway.clients_address(),
|
||||||
@@ -90,59 +86,52 @@ async fn register_with_gateway(
|
|||||||
gateway.owner.clone(),
|
gateway.owner.clone(),
|
||||||
our_identity.clone(),
|
our_identity.clone(),
|
||||||
timeout,
|
timeout,
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
gateway_client
|
gateway_client
|
||||||
.establish_connection()
|
.establish_connection()
|
||||||
.await
|
.await
|
||||||
.tap_err(|_| log::warn!("Failed to establish connection with gateway!"))?;
|
.expect("failed to establish connection with the gateway!");
|
||||||
let shared_keys = gateway_client
|
gateway_client
|
||||||
.perform_initial_authentication()
|
.perform_initial_authentication()
|
||||||
.await
|
.await
|
||||||
.tap_err(|_| log::warn!("Failed to register with the gateway!"))?;
|
.expect("failed to register with the gateway!")
|
||||||
Ok(shared_keys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_address<T>(config: &Config<T>) -> Result<(), ClientCoreError>
|
pub fn show_address<T>(config: &Config<T>)
|
||||||
where
|
where
|
||||||
T: config::NymConfig,
|
T: config::NymConfig,
|
||||||
{
|
{
|
||||||
fn load_identity_keys(
|
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||||
pathfinder: &ClientKeyPathfinder,
|
|
||||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
|
||||||
let identity_keypair: identity::KeyPair =
|
let identity_keypair: identity::KeyPair =
|
||||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
pathfinder.private_identity_key().to_owned(),
|
pathfinder.private_identity_key().to_owned(),
|
||||||
pathfinder.public_identity_key().to_owned(),
|
pathfinder.public_identity_key().to_owned(),
|
||||||
))
|
))
|
||||||
.tap_err(|_| log::error!("Failed to read stored identity key files"))?;
|
.expect("Failed to read stored identity key files");
|
||||||
Ok(identity_keypair)
|
identity_keypair
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_sphinx_keys(
|
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||||
pathfinder: &ClientKeyPathfinder,
|
|
||||||
) -> Result<encryption::KeyPair, ClientCoreError> {
|
|
||||||
let sphinx_keypair: encryption::KeyPair =
|
let sphinx_keypair: encryption::KeyPair =
|
||||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
pathfinder.private_encryption_key().to_owned(),
|
pathfinder.private_encryption_key().to_owned(),
|
||||||
pathfinder.public_encryption_key().to_owned(),
|
pathfinder.public_encryption_key().to_owned(),
|
||||||
))
|
))
|
||||||
.tap_err(|_| log::error!("Failed to read stored sphinx key files"))?;
|
.expect("Failed to read stored sphinx key files");
|
||||||
Ok(sphinx_keypair)
|
sphinx_keypair
|
||||||
}
|
}
|
||||||
|
|
||||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||||
let identity_keypair = load_identity_keys(&pathfinder)?;
|
let identity_keypair = load_identity_keys(&pathfinder);
|
||||||
let sphinx_keypair = load_sphinx_keys(&pathfinder)?;
|
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||||
|
|
||||||
let client_recipient = Recipient::new(
|
let client_recipient = Recipient::new(
|
||||||
*identity_keypair.public_key(),
|
*identity_keypair.public_key(),
|
||||||
*sphinx_keypair.public_key(),
|
*sphinx_keypair.public_key(),
|
||||||
// TODO: below only works under assumption that gateway address == gateway id
|
// TODO: below only works under assumption that gateway address == gateway id
|
||||||
// (which currently is true)
|
// (which currently is true)
|
||||||
NodeIdentity::from_base58_string(config.get_gateway_id())?,
|
NodeIdentity::from_base58_string(config.get_gateway_id()).unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("\nThe address of this client is: {}", client_recipient);
|
println!("\nThe address of this client is: {}", client_recipient);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
|
||||||
pub mod init;
|
pub mod init;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ edition = "2021"
|
|||||||
async-trait = "0.1.52"
|
async-trait = "0.1.52"
|
||||||
bip39 = "1.0.1"
|
bip39 = "1.0.1"
|
||||||
cfg-if = "0.1"
|
cfg-if = "0.1"
|
||||||
clap = { version = "3.2", features = ["cargo", "derive"] }
|
clap = { version = "3.0.10", features = ["cargo", "derive"] }
|
||||||
pickledb = "0.4.1"
|
pickledb = "0.4.1"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
@@ -18,8 +18,6 @@ url = "2.2"
|
|||||||
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||||
|
|
||||||
coconut-interface = { path = "../../common/coconut-interface" }
|
coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
config = { path = "../../common/config" }
|
|
||||||
completions = { path = "../../common/completions" }
|
|
||||||
credentials = { path = "../../common/credentials" }
|
credentials = { path = "../../common/credentials" }
|
||||||
credential-storage = { path = "../../common/credential-storage" }
|
credential-storage = { path = "../../common/credential-storage" }
|
||||||
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
use crate::{MNEMONIC, NYMD_URL};
|
||||||
use bip39::Mnemonic;
|
use bip39::Mnemonic;
|
||||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_client::nymd;
|
use validator_client::nymd;
|
||||||
@@ -12,23 +13,18 @@ use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
|
|||||||
|
|
||||||
pub(crate) struct Client {
|
pub(crate) struct Client {
|
||||||
nymd_client: NymdClient<SigningNymdClient>,
|
nymd_client: NymdClient<SigningNymdClient>,
|
||||||
mix_denom_base: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(nymd_url: &str, mnemonic: &str) -> Self {
|
pub fn new() -> Self {
|
||||||
let nymd_url = Url::from_str(nymd_url).unwrap();
|
let nymd_url = Url::from_str(NYMD_URL).unwrap();
|
||||||
let mnemonic = Mnemonic::from_str(mnemonic).unwrap();
|
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
|
||||||
let network_details = NymNetworkDetails::new_from_env();
|
let config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
|
||||||
let config = nymd::Config::try_from_nym_network_details(&network_details)
|
|
||||||
.expect("failed to construct valid validator client config with the provided network");
|
.expect("failed to construct valid validator client config with the provided network");
|
||||||
let nymd_client =
|
let nymd_client =
|
||||||
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
|
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
|
||||||
|
|
||||||
Client {
|
Client { nymd_client }
|
||||||
nymd_client,
|
|
||||||
mix_denom_base: network_details.chain_details.mix_denom.base,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn deposit(
|
pub async fn deposit(
|
||||||
@@ -38,7 +34,7 @@ impl Client {
|
|||||||
encryption_key: String,
|
encryption_key: String,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let amount = Coin::new(amount as u128, self.mix_denom_base.clone());
|
let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
|
||||||
Ok(self
|
Ok(self
|
||||||
.nymd_client
|
.nymd_client
|
||||||
.deposit(
|
.deposit(
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use clap::{Args, Subcommand};
|
use clap::{Args, Subcommand};
|
||||||
use completions::ArgShell;
|
|
||||||
use pickledb::PickleDb;
|
use pickledb::PickleDb;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use coconut_interface::{Attribute, Base58, BlindSignRequest, Bytable, Parameters};
|
use coconut_interface::{Attribute, Base58, BlindSignRequest, Bytable, Parameters};
|
||||||
use credential_storage::storage::Storage;
|
use credential_storage::storage::Storage;
|
||||||
@@ -20,6 +20,7 @@ use validator_client::nymd::tx::Hash;
|
|||||||
use crate::client::Client;
|
use crate::client::Client;
|
||||||
use crate::error::{CredentialClientError, Result};
|
use crate::error::{CredentialClientError, Result};
|
||||||
use crate::state::{KeyPair, RequestData, State};
|
use crate::state::{KeyPair, RequestData, State};
|
||||||
|
use crate::SIGNER_AUTHORITIES;
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub(crate) enum Commands {
|
pub(crate) enum Commands {
|
||||||
@@ -29,12 +30,6 @@ pub(crate) enum Commands {
|
|||||||
ListDeposits(ListDeposits),
|
ListDeposits(ListDeposits),
|
||||||
/// Get a credential for a given deposit
|
/// Get a credential for a given deposit
|
||||||
GetCredential(GetCredential),
|
GetCredential(GetCredential),
|
||||||
|
|
||||||
/// Generate shell completions
|
|
||||||
Completions(ArgShell),
|
|
||||||
|
|
||||||
/// Generate Fig specification
|
|
||||||
GenerateFigSpec,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -44,12 +39,6 @@ pub(crate) trait Execute {
|
|||||||
|
|
||||||
#[derive(Args, Clone)]
|
#[derive(Args, Clone)]
|
||||||
pub(crate) struct Deposit {
|
pub(crate) struct Deposit {
|
||||||
/// The nymd URL that should be used
|
|
||||||
#[clap(long)]
|
|
||||||
nymd_url: String,
|
|
||||||
/// A mnemonic for the account that does the deposit
|
|
||||||
#[clap(long)]
|
|
||||||
mnemonic: String,
|
|
||||||
/// The amount that needs to be deposited
|
/// The amount that needs to be deposited
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
amount: u64,
|
amount: u64,
|
||||||
@@ -62,7 +51,7 @@ impl Execute for Deposit {
|
|||||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||||
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
||||||
|
|
||||||
let client = Client::new(&self.nymd_url, &self.mnemonic);
|
let client = Client::new();
|
||||||
let tx_hash = client
|
let tx_hash = client
|
||||||
.deposit(
|
.deposit(
|
||||||
self.amount,
|
self.amount,
|
||||||
@@ -107,10 +96,6 @@ pub(crate) struct GetCredential {
|
|||||||
/// The hash of a successful deposit transaction
|
/// The hash of a successful deposit transaction
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
tx_hash: String,
|
tx_hash: String,
|
||||||
/// The URLs to the validator-api endpoints the are run as coconut signer authorities, separated
|
|
||||||
/// by comma (,)
|
|
||||||
#[clap(long)]
|
|
||||||
signer_authorities: String,
|
|
||||||
/// If we want to get the signature without attaching a blind sign request; it is expected that
|
/// If we want to get the signature without attaching a blind sign request; it is expected that
|
||||||
/// there is already a signature stored on the signer
|
/// there is already a signature stored on the signer
|
||||||
#[clap(long, parse(from_flag))]
|
#[clap(long, parse(from_flag))]
|
||||||
@@ -123,8 +108,7 @@ impl Execute for GetCredential {
|
|||||||
let mut state = db
|
let mut state = db
|
||||||
.get::<State>(&self.tx_hash)
|
.get::<State>(&self.tx_hash)
|
||||||
.ok_or(CredentialClientError::NoDeposit)?;
|
.ok_or(CredentialClientError::NoDeposit)?;
|
||||||
|
let urls = SIGNER_AUTHORITIES.map(|addr| Url::from_str(addr).unwrap());
|
||||||
let urls = config::parse_validators(&self.signer_authorities);
|
|
||||||
|
|
||||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||||
let bandwidth_credential_attributes = if self.__no_request {
|
let bandwidth_credential_attributes = if self.__no_request {
|
||||||
|
|||||||
@@ -11,26 +11,20 @@ cfg_if::cfg_if! {
|
|||||||
|
|
||||||
use commands::{Commands, Execute};
|
use commands::{Commands, Execute};
|
||||||
use error::Result;
|
use error::Result;
|
||||||
use network_defaults::setup_env;
|
|
||||||
use clap::CommandFactory;
|
|
||||||
use completions::fig_generate;
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
|
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
|
||||||
|
|
||||||
|
pub const MNEMONIC: &str = "jazz fatigue diagram account outer wrist slide cherry mother grid network pause wolf pig round answer mail junior better hair dismiss toward access end";
|
||||||
|
pub const NYMD_URL: &str = "http://127.0.0.1:26657";
|
||||||
|
pub const CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
|
||||||
|
pub const SIGNER_AUTHORITIES: [&str; 1] = [
|
||||||
|
"http://127.0.0.1:8080",
|
||||||
|
];
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author = "Nymtech", version, about)]
|
#[clap(author = "Nymtech", version, about)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
/// Path pointing to an env file that configures the client.
|
|
||||||
#[clap(long)]
|
|
||||||
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
|
||||||
|
|
||||||
/// Path where the sqlite credental database will be located.
|
|
||||||
/// It should point to a $HOME/$CLIENT_ID/data/db.sqlite file of
|
|
||||||
/// the client that is supposed to use the credential.
|
|
||||||
#[clap(long)]
|
|
||||||
pub(crate) credential_db_path: std::path::PathBuf,
|
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
}
|
}
|
||||||
@@ -38,9 +32,8 @@ cfg_if::cfg_if! {
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
setup_env(args.config_env_file.clone());
|
|
||||||
|
|
||||||
let shared_storage = credential_storage::initialise_storage(args.credential_db_path.clone()).await;
|
let shared_storage = credential_storage::initialise_storage(std::path::PathBuf::from("/tmp/credential.db")).await;
|
||||||
let mut db = match PickleDb::load(
|
let mut db = match PickleDb::load(
|
||||||
"credential.db",
|
"credential.db",
|
||||||
PickleDbDumpPolicy::AutoDump,
|
PickleDbDumpPolicy::AutoDump,
|
||||||
@@ -54,14 +47,10 @@ cfg_if::cfg_if! {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let bin_name = "nym-credential-client";
|
|
||||||
|
|
||||||
match &args.command {
|
match &args.command {
|
||||||
Commands::Deposit(m) => m.execute(&mut db, shared_storage).await?,
|
Commands::Deposit(m) => m.execute(&mut db, shared_storage).await?,
|
||||||
Commands::ListDeposits(m) => m.execute(&mut db, shared_storage).await?,
|
Commands::ListDeposits(m) => m.execute(&mut db, shared_storage).await?,
|
||||||
Commands::GetCredential(m) => m.execute(&mut db, shared_storage).await?,
|
Commands::GetCredential(m) => m.execute(&mut db, shared_storage).await?,
|
||||||
Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name),
|
|
||||||
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.0.2"
|
version = "1.0.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Client"
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -20,8 +20,9 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
|
|||||||
# and the single instance of abortable we have should really be refactored anyway
|
# and the single instance of abortable we have should really be refactored anyway
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
clap = { version = "3.2", features = ["cargo", "derive"] }
|
clap = { version = "3.2.8", features = ["cargo", "derive"] }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
|
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
||||||
log = "0.4" # self explanatory
|
log = "0.4" # self explanatory
|
||||||
pretty_env_logger = "0.4" # for formatting log messages
|
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
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
|
||||||
@@ -33,24 +34,23 @@ tokio-tungstenite = "0.14" # websocket
|
|||||||
## internal
|
## internal
|
||||||
client-core = { path = "../client-core" }
|
client-core = { path = "../client-core" }
|
||||||
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
||||||
config = { path = "../../common/config" }
|
|
||||||
completions = { path = "../../common/completions" }
|
|
||||||
credential-storage = { path = "../../common/credential-storage" }
|
|
||||||
credentials = { path = "../../common/credentials", optional = true }
|
credentials = { path = "../../common/credentials", optional = true }
|
||||||
|
credential-storage = { path = "../../common/credential-storage" }
|
||||||
|
config = { path = "../../common/config" }
|
||||||
crypto = { path = "../../common/crypto" }
|
crypto = { path = "../../common/crypto" }
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
network-defaults = { path = "../../common/network-defaults" }
|
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nymsphinx = { path = "../../common/nymsphinx" }
|
||||||
pemstore = { path = "../../common/pemstore" }
|
pemstore = { path = "../../common/pemstore" }
|
||||||
task = { path = "../../common/task" }
|
|
||||||
topology = { path = "../../common/topology" }
|
topology = { path = "../../common/topology" }
|
||||||
|
websocket-requests = { path = "websocket-requests" }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
|
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
|
||||||
version-checker = { path = "../../common/version-checker" }
|
version-checker = { path = "../../common/version-checker" }
|
||||||
websocket-requests = { path = "websocket-requests" }
|
network-defaults = { path = "../../common/network-defaults" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
coconut = ["coconut-interface", "credentials", "credentials/coconut", "gateway-requests/coconut", "gateway-client/coconut", "client-core/coconut"]
|
coconut = ["coconut-interface", "credentials", "credentials/coconut", "gateway-requests/coconut", "gateway-client/coconut", "client-core/coconut"]
|
||||||
|
eth = []
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1.0" # for the "textsend" example
|
serde_json = "1.0" # for the "textsend" example
|
||||||
|
|||||||
+21
-103
@@ -27,58 +27,6 @@
|
|||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/set-array": "^1.0.1",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/set-array": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/source-map": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/gen-mapping": "^0.3.0",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
|
||||||
"version": "1.4.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
|
||||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
|
||||||
"version": "0.3.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
|
|
||||||
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@@ -3581,13 +3529,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.15.0",
|
"version": "5.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz",
|
||||||
"integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==",
|
"integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^8.5.0",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
|
"source-map": "~0.7.2",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -3635,6 +3583,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/terser/node_modules/source-map": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/thunky": {
|
"node_modules/thunky": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
||||||
@@ -4374,49 +4330,6 @@
|
|||||||
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
|
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@jridgewell/gen-mapping": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
|
||||||
"requires": {
|
|
||||||
"@jridgewell/set-array": "^1.0.1",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@jridgewell/resolve-uri": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
|
|
||||||
},
|
|
||||||
"@jridgewell/set-array": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
|
|
||||||
},
|
|
||||||
"@jridgewell/source-map": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
|
||||||
"requires": {
|
|
||||||
"@jridgewell/gen-mapping": "^0.3.0",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@jridgewell/sourcemap-codec": {
|
|
||||||
"version": "1.4.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
|
||||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
|
||||||
},
|
|
||||||
"@jridgewell/trace-mapping": {
|
|
||||||
"version": "0.3.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
|
|
||||||
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
|
|
||||||
"requires": {
|
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@nodelib/fs.scandir": {
|
"@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@@ -7145,13 +7058,13 @@
|
|||||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="
|
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "5.15.0",
|
"version": "5.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz",
|
||||||
"integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==",
|
"integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^8.5.0",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
|
"source-map": "~0.7.2",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -7159,6 +7072,11 @@
|
|||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
|
},
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ impl NymConfig for Config {
|
|||||||
.join("clients")
|
.join("clients")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_default_root_directory() -> Option<PathBuf> {
|
|
||||||
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn root_directory(&self) -> PathBuf {
|
fn root_directory(&self) -> PathBuf {
|
||||||
self.base.get_nym_root_directory()
|
self.base.get_nym_root_directory()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
|||||||
# Path to the database containing bandwidth credentials
|
# Path to the database containing bandwidth credentials
|
||||||
database_path = '{{ client.database_path }}'
|
database_path = '{{ client.database_path }}'
|
||||||
|
|
||||||
|
# Ethereum private key.
|
||||||
|
eth_private_key = '{{ client.eth_private_key }}'
|
||||||
|
|
||||||
|
# Addess to an Ethereum full node.
|
||||||
|
eth_endpoint = '{{ client.eth_endpoint }}'
|
||||||
|
|
||||||
##### additional client config options #####
|
##### additional client config options #####
|
||||||
|
|
||||||
# A gateway specific, optional, base58 stringified shared key used for
|
# A gateway specific, optional, base58 stringified shared key used for
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ use nymsphinx::addressing::clients::Recipient;
|
|||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
use nymsphinx::anonymous_replies::ReplySurb;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
use nymsphinx::receiver::ReconstructedMessage;
|
||||||
use task::{wait_for_signal, ShutdownListener, ShutdownNotifier};
|
|
||||||
|
|
||||||
use crate::client::config::{Config, SocketType};
|
use crate::client::config::{Config, SocketType};
|
||||||
use crate::websocket;
|
use crate::websocket;
|
||||||
@@ -86,7 +85,6 @@ impl NymClient {
|
|||||||
&self,
|
&self,
|
||||||
topology_accessor: TopologyAccessor,
|
topology_accessor: TopologyAccessor,
|
||||||
mix_tx: BatchMixMessageSender,
|
mix_tx: BatchMixMessageSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting loop cover traffic stream...");
|
info!("Starting loop cover traffic stream...");
|
||||||
|
|
||||||
@@ -100,7 +98,6 @@ impl NymClient {
|
|||||||
mix_tx,
|
mix_tx,
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
shutdown,
|
|
||||||
)
|
)
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
@@ -112,7 +109,6 @@ impl NymClient {
|
|||||||
ack_receiver: AcknowledgementReceiver,
|
ack_receiver: AcknowledgementReceiver,
|
||||||
input_receiver: InputMessageReceiver,
|
input_receiver: InputMessageReceiver,
|
||||||
mix_sender: BatchMixMessageSender,
|
mix_sender: BatchMixMessageSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
let controller_config = real_messages_control::Config::new(
|
let controller_config = real_messages_control::Config::new(
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
@@ -133,7 +129,6 @@ impl NymClient {
|
|||||||
mix_sender,
|
mix_sender,
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
shutdown,
|
|
||||||
)
|
)
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
@@ -145,7 +140,6 @@ impl NymClient {
|
|||||||
query_receiver: ReceivedBufferRequestReceiver,
|
query_receiver: ReceivedBufferRequestReceiver,
|
||||||
mixnet_receiver: MixnetMessageReceiver,
|
mixnet_receiver: MixnetMessageReceiver,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting received messages buffer controller...");
|
info!("Starting received messages buffer controller...");
|
||||||
ReceivedMessagesBufferController::new(
|
ReceivedMessagesBufferController::new(
|
||||||
@@ -153,7 +147,6 @@ impl NymClient {
|
|||||||
query_receiver,
|
query_receiver,
|
||||||
mixnet_receiver,
|
mixnet_receiver,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
shutdown,
|
|
||||||
)
|
)
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
@@ -162,7 +155,6 @@ impl NymClient {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mixnet_message_sender: MixnetMessageSender,
|
mixnet_message_sender: MixnetMessageSender,
|
||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> GatewayClient {
|
) -> GatewayClient {
|
||||||
let gateway_id = self.config.get_base().get_gateway_id();
|
let gateway_id = self.config.get_base().get_gateway_id();
|
||||||
if gateway_id.is_empty() {
|
if gateway_id.is_empty() {
|
||||||
@@ -190,6 +182,8 @@ impl NymClient {
|
|||||||
let bandwidth_controller = BandwidthController::new(
|
let bandwidth_controller = BandwidthController::new(
|
||||||
credential_storage::initialise_storage(self.config.get_base().get_database_path())
|
credential_storage::initialise_storage(self.config.get_base().get_database_path())
|
||||||
.await,
|
.await,
|
||||||
|
self.config.get_base().get_eth_endpoint(),
|
||||||
|
self.config.get_base().get_eth_private_key(),
|
||||||
)
|
)
|
||||||
.expect("Could not create bandwidth controller");
|
.expect("Could not create bandwidth controller");
|
||||||
|
|
||||||
@@ -203,12 +197,11 @@ impl NymClient {
|
|||||||
ack_sender,
|
ack_sender,
|
||||||
self.config.get_base().get_gateway_response_timeout(),
|
self.config.get_base().get_gateway_response_timeout(),
|
||||||
Some(bandwidth_controller),
|
Some(bandwidth_controller),
|
||||||
Some(shutdown),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
gateway_client
|
if self.config.get_base().get_disabled_credentials_mode() {
|
||||||
.set_disabled_credentials_mode(self.config.get_base().get_disabled_credentials_mode());
|
gateway_client.set_disabled_credentials_mode(true)
|
||||||
|
}
|
||||||
gateway_client
|
gateway_client
|
||||||
.authenticate_and_start()
|
.authenticate_and_start()
|
||||||
.await
|
.await
|
||||||
@@ -219,11 +212,7 @@ impl NymClient {
|
|||||||
|
|
||||||
// future responsible for periodically polling directory server and updating
|
// future responsible for periodically polling directory server and updating
|
||||||
// the current global view of topology
|
// the current global view of topology
|
||||||
async fn start_topology_refresher(
|
async fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||||
&mut self,
|
|
||||||
topology_accessor: TopologyAccessor,
|
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
|
||||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||||
self.config.get_base().get_validator_api_endpoints(),
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
self.config.get_base().get_topology_refresh_rate(),
|
self.config.get_base().get_topology_refresh_rate(),
|
||||||
@@ -245,7 +234,7 @@ impl NymClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("Starting topology refresher...");
|
info!("Starting topology refresher...");
|
||||||
topology_refresher.start(shutdown);
|
topology_refresher.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
||||||
@@ -256,10 +245,9 @@ impl NymClient {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mix_rx: BatchMixMessageReceiver,
|
mix_rx: BatchMixMessageReceiver,
|
||||||
gateway_client: GatewayClient,
|
gateway_client: GatewayClient,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting mix traffic controller...");
|
info!("Starting mix traffic controller...");
|
||||||
MixTrafficController::new(mix_rx, gateway_client, shutdown).start();
|
MixTrafficController::new(mix_rx, gateway_client).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_websocket_listener(
|
fn start_websocket_listener(
|
||||||
@@ -320,26 +308,20 @@ impl NymClient {
|
|||||||
|
|
||||||
/// blocking version of `start` method. Will run forever (or until SIGINT is sent)
|
/// blocking version of `start` method. Will run forever (or until SIGINT is sent)
|
||||||
pub async fn run_forever(&mut self) {
|
pub async fn run_forever(&mut self) {
|
||||||
let shutdown = self.start().await;
|
self.start().await;
|
||||||
wait_for_signal().await;
|
if let Err(e) = tokio::signal::ctrl_c().await {
|
||||||
|
error!(
|
||||||
|
"There was an error while capturing SIGINT - {:?}. We will terminate regardless",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Received signal - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
|
"Received SIGINT - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
|
||||||
);
|
);
|
||||||
|
|
||||||
log::info!("Sending shutdown");
|
|
||||||
shutdown.signal_shutdown().ok();
|
|
||||||
|
|
||||||
// Some of these components have shutdown signalling implemented as part of socks5 work,
|
|
||||||
// but since it's not fully implemented (yet) for all the components of the native client,
|
|
||||||
// we don't try to wait and instead just stop immediately.
|
|
||||||
//log::info!("Waiting for tasks to finish... (Press ctrl-c to force)");
|
|
||||||
//shutdown.wait_for_shutdown().await;
|
|
||||||
|
|
||||||
log::info!("Stopping nym-client");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(&mut self) -> ShutdownNotifier {
|
pub async fn start(&mut self) {
|
||||||
info!("Starting nym client");
|
info!("Starting nym client");
|
||||||
// channels for inter-component communication
|
// channels for inter-component communication
|
||||||
// TODO: make the channels be internally created by the relevant components
|
// TODO: make the channels be internally created by the relevant components
|
||||||
@@ -369,43 +351,30 @@ impl NymClient {
|
|||||||
ReplyKeyStorage::load(self.config.get_base().get_reply_encryption_key_store_path())
|
ReplyKeyStorage::load(self.config.get_base().get_reply_encryption_key_store_path())
|
||||||
.expect("Failed to load reply key storage!");
|
.expect("Failed to load reply key storage!");
|
||||||
|
|
||||||
// Shutdown notifier for signalling tasks to stop
|
|
||||||
let shutdown = ShutdownNotifier::default();
|
|
||||||
|
|
||||||
// the components are started in very specific order. Unless you know what you are doing,
|
// the components are started in very specific order. Unless you know what you are doing,
|
||||||
// do not change that.
|
// do not change that.
|
||||||
self.start_topology_refresher(shared_topology_accessor.clone(), shutdown.subscribe())
|
self.start_topology_refresher(shared_topology_accessor.clone())
|
||||||
.await;
|
.await;
|
||||||
self.start_received_messages_buffer_controller(
|
self.start_received_messages_buffer_controller(
|
||||||
received_buffer_request_receiver,
|
received_buffer_request_receiver,
|
||||||
mixnet_messages_receiver,
|
mixnet_messages_receiver,
|
||||||
reply_key_storage.clone(),
|
reply_key_storage.clone(),
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_client = self
|
let gateway_client = self
|
||||||
.start_gateway_client(mixnet_messages_sender, ack_sender, shutdown.subscribe())
|
.start_gateway_client(mixnet_messages_sender, ack_sender)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
self.start_mix_traffic_controller(
|
self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client);
|
||||||
sphinx_message_receiver,
|
|
||||||
gateway_client,
|
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
|
||||||
self.start_real_traffic_controller(
|
self.start_real_traffic_controller(
|
||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
ack_receiver,
|
ack_receiver,
|
||||||
input_receiver,
|
input_receiver,
|
||||||
sphinx_message_sender.clone(),
|
sphinx_message_sender.clone(),
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
self.start_cover_traffic_stream(
|
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||||
shared_topology_accessor,
|
|
||||||
sphinx_message_sender,
|
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
|
||||||
|
|
||||||
match self.config.get_socket_type() {
|
match self.config.get_socket_type() {
|
||||||
SocketType::WebSocket => {
|
SocketType::WebSocket => {
|
||||||
@@ -430,7 +399,5 @@ impl NymClient {
|
|||||||
|
|
||||||
info!("Client startup finished!");
|
info!("Client startup finished!");
|
||||||
info!("The address of this client is: {}", self.as_mix_recipient());
|
info!("The address of this client is: {}", self.as_mix_recipient());
|
||||||
|
|
||||||
shutdown
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use client_core::{config::GatewayEndpoint, error::ClientCoreError};
|
use client_core::config::GatewayEndpoint;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -10,6 +10,9 @@ use crate::{
|
|||||||
commands::{override_config, OverrideConfig},
|
commands::{override_config, OverrideConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
#[derive(Args, Clone)]
|
||||||
pub(crate) struct Init {
|
pub(crate) struct Init {
|
||||||
/// Id of the nym-mixnet-client we want to create config for.
|
/// Id of the nym-mixnet-client we want to create config for.
|
||||||
@@ -43,10 +46,29 @@ pub(crate) struct Init {
|
|||||||
fastmode: bool,
|
fastmode: bool,
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
/// with bandwidth credential requirement.
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
#[cfg(feature = "coconut")]
|
/// --eth-private_key don't need to be set.
|
||||||
#[clap(long)]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
enabled_credentials_mode: bool,
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_ENDPOINT))
|
||||||
|
)]
|
||||||
|
eth_endpoint: String,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead")
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_PRIVATE_KEY))
|
||||||
|
)]
|
||||||
|
eth_private_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Init> for OverrideConfig {
|
impl From<Init> for OverrideConfig {
|
||||||
@@ -57,8 +79,14 @@ impl From<Init> for OverrideConfig {
|
|||||||
port: init_config.port,
|
port: init_config.port,
|
||||||
fastmode: init_config.fastmode,
|
fastmode: init_config.fastmode,
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Some(init_config.eth_private_key),
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Some(init_config.eth_endpoint),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,12 +121,7 @@ pub(crate) async fn execute(args: &Init) {
|
|||||||
let override_config_fields = OverrideConfig::from(args.clone());
|
let override_config_fields = OverrideConfig::from(args.clone());
|
||||||
config = override_config(config, override_config_fields);
|
config = override_config(config, override_config_fields);
|
||||||
|
|
||||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config)
|
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
eprintln!("Failed to setup gateway\nError: {err}");
|
|
||||||
std::process::exit(1)
|
|
||||||
});
|
|
||||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||||
|
|
||||||
let config_save_location = config.get_config_file_save_location();
|
let config_save_location = config.get_config_file_save_location();
|
||||||
@@ -116,10 +139,7 @@ pub(crate) async fn execute(args: &Init) {
|
|||||||
);
|
);
|
||||||
println!("Client configuration completed.");
|
println!("Client configuration completed.");
|
||||||
|
|
||||||
client_core::init::show_address(config.get_base()).unwrap_or_else(|err| {
|
client_core::init::show_address(config.get_base());
|
||||||
eprintln!("Failed to show address\nError: {err}");
|
|
||||||
std::process::exit(1)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_gateway(
|
async fn setup_gateway(
|
||||||
@@ -127,7 +147,7 @@ async fn setup_gateway(
|
|||||||
register: bool,
|
register: bool,
|
||||||
user_chosen_gateway_id: Option<&str>,
|
user_chosen_gateway_id: Option<&str>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> Result<GatewayEndpoint, ClientCoreError> {
|
) -> GatewayEndpoint {
|
||||||
if register {
|
if register {
|
||||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||||
// the chosen one if it's among the available ones.
|
// the chosen one if it's among the available ones.
|
||||||
@@ -136,16 +156,16 @@ async fn setup_gateway(
|
|||||||
config.get_base().get_validator_api_endpoints(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
user_chosen_gateway_id,
|
user_chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
log::debug!("Querying gateway gives: {}", gateway);
|
||||||
|
|
||||||
// Registering with gateway by setting up and writing shared keys to disk
|
// Registering with gateway by setting up and writing shared keys to disk
|
||||||
log::trace!("Registering gateway");
|
log::trace!("Registering gateway");
|
||||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||||
.await?;
|
.await;
|
||||||
println!("Saved all generated keys");
|
println!("Saved all generated keys");
|
||||||
|
|
||||||
Ok(gateway.into())
|
gateway.into()
|
||||||
} else if user_chosen_gateway_id.is_some() {
|
} else if user_chosen_gateway_id.is_some() {
|
||||||
// Just set the config, don't register or create any keys
|
// Just set the config, don't register or create any keys
|
||||||
// This assumes that the user knows what they are doing, and that the existing keys are
|
// This assumes that the user knows what they are doing, and that the existing keys are
|
||||||
@@ -155,22 +175,22 @@ async fn setup_gateway(
|
|||||||
config.get_base().get_validator_api_endpoints(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
user_chosen_gateway_id,
|
user_chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
log::debug!("Querying gateway gives: {}", gateway);
|
||||||
Ok(gateway.into())
|
gateway.into()
|
||||||
} else {
|
} else {
|
||||||
println!("Not registering gateway, will reuse existing config and keys");
|
println!("Not registering gateway, will reuse existing config and keys");
|
||||||
let existing_config = Config::load_from_file(Some(id)).map_err(|err| {
|
match Config::load_from_file(Some(id)) {
|
||||||
log::error!(
|
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
|
||||||
"Unable to configure gateway: {err}. \n
|
Err(err) => {
|
||||||
Seems like the client was already initialized but it was not possible to read \
|
panic!(
|
||||||
the existing configuration file. \n
|
"Unable to configure gateway: {err}. \n
|
||||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
Seems like the client was already initialized but it was not possible to read \
|
||||||
removing the existing configuration and starting over."
|
the existing configuration file. \n
|
||||||
);
|
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||||
ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err)
|
removing the existing configuration and starting over."
|
||||||
})?;
|
)
|
||||||
|
}
|
||||||
Ok(existing_config.get_base().get_gateway_endpoint().clone())
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,16 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::{Config, SocketType};
|
use crate::client::config::{Config, SocketType};
|
||||||
use clap::CommandFactory;
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use completions::{fig_generate, ArgShell};
|
use network_defaults::DEFAULT_NETWORK;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
||||||
|
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001";
|
||||||
|
|
||||||
pub(crate) mod init;
|
pub(crate) mod init;
|
||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
@@ -21,6 +28,7 @@ fn long_version() -> String {
|
|||||||
{:<20}{}
|
{:<20}{}
|
||||||
{:<20}{}
|
{:<20}{}
|
||||||
{:<20}{}
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
"#,
|
"#,
|
||||||
"Build Timestamp:",
|
"Build Timestamp:",
|
||||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
@@ -38,6 +46,8 @@ fn long_version() -> String {
|
|||||||
env!("VERGEN_RUSTC_CHANNEL"),
|
env!("VERGEN_RUSTC_CHANNEL"),
|
||||||
"cargo Profile:",
|
"cargo Profile:",
|
||||||
env!("VERGEN_CARGO_PROFILE"),
|
env!("VERGEN_CARGO_PROFILE"),
|
||||||
|
"Network:",
|
||||||
|
DEFAULT_NETWORK
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,10 +58,6 @@ fn long_version_static() -> &'static str {
|
|||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
||||||
pub(crate) struct Cli {
|
pub(crate) struct Cli {
|
||||||
/// Path pointing to an env file that configures the client.
|
|
||||||
#[clap(long)]
|
|
||||||
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
}
|
}
|
||||||
@@ -64,12 +70,6 @@ pub(crate) enum Commands {
|
|||||||
Run(run::Run),
|
Run(run::Run),
|
||||||
/// Try to upgrade the client
|
/// Try to upgrade the client
|
||||||
Upgrade(upgrade::Upgrade),
|
Upgrade(upgrade::Upgrade),
|
||||||
|
|
||||||
/// Generate shell completions
|
|
||||||
Completions(ArgShell),
|
|
||||||
|
|
||||||
/// Generate Fig specification
|
|
||||||
GenerateFigSpec,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration that can be overridden.
|
// Configuration that can be overridden.
|
||||||
@@ -79,33 +79,40 @@ pub(crate) struct OverrideConfig {
|
|||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
fastmode: bool,
|
fastmode: bool,
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
enabled_credentials_mode: bool,
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Cli) {
|
pub(crate) async fn execute(args: &Cli) {
|
||||||
let bin_name = "nym-native-client";
|
|
||||||
|
|
||||||
match &args.command {
|
match &args.command {
|
||||||
Commands::Init(m) => init::execute(m).await,
|
Commands::Init(m) => init::execute(m).await,
|
||||||
Commands::Run(m) => run::execute(m).await,
|
Commands::Run(m) => run::execute(m).await,
|
||||||
Commands::Upgrade(m) => upgrade::execute(m),
|
Commands::Upgrade(m) => upgrade::execute(m),
|
||||||
Commands::Completions(s) => s.generate(&mut Cli::into_app(), bin_name),
|
|
||||||
Commands::GenerateFigSpec => fig_generate(&mut Cli::into_app(), bin_name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
|
raw.split(',')
|
||||||
|
.map(|raw_validator| {
|
||||||
|
raw_validator
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("one of the provided validator api urls is invalid")
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
||||||
if let Some(raw_validators) = args.validators {
|
if let Some(raw_validators) = args.validators {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_validator_apis(config::parse_validators(&raw_validators));
|
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||||
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
|
|
||||||
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
|
|
||||||
.expect("api validator not set");
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validator_apis(config::parse_validators(&raw_validators));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.disable_socket {
|
if args.disable_socket {
|
||||||
@@ -116,11 +123,27 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
|
|||||||
config = config.with_port(port);
|
config = config.with_port(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
{
|
{
|
||||||
if args.enabled_credentials_mode {
|
if args.enabled_credentials_mode {
|
||||||
config.get_base_mut().with_disabled_credentials(false)
|
config.get_base_mut().with_disabled_credentials(false)
|
||||||
}
|
}
|
||||||
|
if let Some(eth_endpoint) = args.eth_endpoint {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
}
|
||||||
|
if let Some(eth_private_key) = args.eth_private_key {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.fastmode {
|
if args.fastmode {
|
||||||
|
|||||||
@@ -35,10 +35,23 @@ pub(crate) struct Run {
|
|||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
/// with bandwidth credential requirement.
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
#[cfg(feature = "coconut")]
|
/// --eth-private-key don't need to be set.
|
||||||
#[clap(long)]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
enabled_credentials_mode: bool,
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead")
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Run> for OverrideConfig {
|
impl From<Run> for OverrideConfig {
|
||||||
@@ -48,8 +61,15 @@ impl From<Run> for OverrideConfig {
|
|||||||
disable_socket: run_config.disable_socket,
|
disable_socket: run_config.disable_socket,
|
||||||
port: run_config.port,
|
port: run_config.port,
|
||||||
fastmode: false,
|
fastmode: false,
|
||||||
#[cfg(feature = "coconut")]
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: run_config.eth_private_key,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: run_config.eth_endpoint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +82,7 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
if binary_version == config_version {
|
if binary_version == config_version {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
warn!("The native-client binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
||||||
if is_minor_version_compatible(binary_version, config_version) {
|
if is_minor_version_compatible(binary_version, config_version) {
|
||||||
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
|
|
||||||
use config::NymConfig;
|
use config::{defaults::default_api_endpoints, NymConfig};
|
||||||
use version_checker::Version;
|
use version_checker::Version;
|
||||||
|
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
@@ -103,7 +103,16 @@ fn minor_0_12_upgrade(
|
|||||||
Version::new(0, 12, 0)
|
Version::new(0, 12, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
print_start_upgrade(config_version, &to_version);
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Setting validator API endpoints to {:?}",
|
||||||
|
default_api_endpoints()
|
||||||
|
);
|
||||||
|
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(default_api_endpoints());
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
@@ -111,7 +120,7 @@ fn minor_0_12_upgrade(
|
|||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
config.save_to_file(None).unwrap_or_else(|err| {
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||||
print_failed_upgrade(config_version, &to_version);
|
print_failed_upgrade(&config_version, &to_version);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{crate_version, Parser};
|
use clap::{crate_version, Parser};
|
||||||
use network_defaults::setup_env;
|
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
@@ -10,11 +9,11 @@ pub mod websocket;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
dotenv::dotenv().ok();
|
||||||
setup_logging();
|
setup_logging();
|
||||||
println!("{}", banner());
|
println!("{}", banner());
|
||||||
|
|
||||||
let args = commands::Cli::parse();
|
let args = commands::Cli::parse();
|
||||||
setup_env(args.config_env_file.clone());
|
|
||||||
commands::execute(&args).await;
|
commands::execute(&args).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.0.2"
|
version = "1.0.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -11,8 +11,9 @@ name = "nym_socks5"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.2", features = ["cargo", "derive"] }
|
clap = { version = "3.2.8", features = ["cargo", "derive"] }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
|
dotenv = "0.15.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pin-project = "1.0"
|
pin-project = "1.0"
|
||||||
@@ -26,23 +27,21 @@ url = "2.2"
|
|||||||
# internal
|
# internal
|
||||||
client-core = { path = "../client-core" }
|
client-core = { path = "../client-core" }
|
||||||
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
||||||
config = { path = "../../common/config" }
|
|
||||||
completions = { path = "../../common/completions" }
|
|
||||||
credential-storage = { path = "../../common/credential-storage" }
|
|
||||||
credentials = { path = "../../common/credentials", optional = true }
|
credentials = { path = "../../common/credentials", optional = true }
|
||||||
|
credential-storage = { path = "../../common/credential-storage" }
|
||||||
|
config = { path = "../../common/config" }
|
||||||
crypto = { path = "../../common/crypto" }
|
crypto = { path = "../../common/crypto" }
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
network-defaults = { path = "../../common/network-defaults" }
|
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nymsphinx = { path = "../../common/nymsphinx" }
|
||||||
ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||||
|
socks5-requests = { path = "../../common/socks5/requests" }
|
||||||
|
topology = { path = "../../common/topology" }
|
||||||
pemstore = { path = "../../common/pemstore" }
|
pemstore = { path = "../../common/pemstore" }
|
||||||
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
||||||
socks5-requests = { path = "../../common/socks5/requests" }
|
|
||||||
task = { path = "../../common/task" }
|
|
||||||
topology = { path = "../../common/topology" }
|
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
|
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
|
||||||
version-checker = { path = "../../common/version-checker" }
|
version-checker = { path = "../../common/version-checker" }
|
||||||
|
network-defaults = { path = "../../common/network-defaults" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut", "client-core/coconut"]
|
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut", "client-core/coconut"]
|
||||||
|
|||||||
@@ -33,10 +33,6 @@ impl NymConfig for Config {
|
|||||||
.join("socks5-clients")
|
.join("socks5-clients")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_default_root_directory() -> Option<PathBuf> {
|
|
||||||
dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn root_directory(&self) -> PathBuf {
|
fn root_directory(&self) -> PathBuf {
|
||||||
self.base.get_nym_root_directory()
|
self.base.get_nym_root_directory()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
|||||||
# Path to the database containing bandwidth credentials
|
# Path to the database containing bandwidth credentials
|
||||||
database_path = '{{ client.database_path }}'
|
database_path = '{{ client.database_path }}'
|
||||||
|
|
||||||
|
# Ethereum private key.
|
||||||
|
eth_private_key = '{{ client.eth_private_key }}'
|
||||||
|
|
||||||
|
# Addess to an Ethereum full node.
|
||||||
|
eth_endpoint = '{{ client.eth_endpoint }}'
|
||||||
|
|
||||||
##### additional client config options #####
|
##### additional client config options #####
|
||||||
|
|
||||||
# A gateway specific, optional, base58 stringified shared key used for
|
# A gateway specific, optional, base58 stringified shared key used for
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||||
use client_core::client::inbound_messages::{
|
use client_core::client::inbound_messages::{
|
||||||
InputMessage, InputMessageReceiver, InputMessageSender,
|
InputMessage, InputMessageReceiver, InputMessageSender,
|
||||||
@@ -31,7 +29,6 @@ use gateway_client::{
|
|||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
use task::{wait_for_signal, ShutdownListener, ShutdownNotifier};
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use crate::socks::{
|
use crate::socks::{
|
||||||
@@ -87,7 +84,6 @@ impl NymClient {
|
|||||||
&self,
|
&self,
|
||||||
topology_accessor: TopologyAccessor,
|
topology_accessor: TopologyAccessor,
|
||||||
mix_tx: BatchMixMessageSender,
|
mix_tx: BatchMixMessageSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting loop cover traffic stream...");
|
info!("Starting loop cover traffic stream...");
|
||||||
|
|
||||||
@@ -101,7 +97,6 @@ impl NymClient {
|
|||||||
mix_tx,
|
mix_tx,
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
shutdown,
|
|
||||||
)
|
)
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
@@ -113,7 +108,6 @@ impl NymClient {
|
|||||||
ack_receiver: AcknowledgementReceiver,
|
ack_receiver: AcknowledgementReceiver,
|
||||||
input_receiver: InputMessageReceiver,
|
input_receiver: InputMessageReceiver,
|
||||||
mix_sender: BatchMixMessageSender,
|
mix_sender: BatchMixMessageSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
let controller_config = client_core::client::real_messages_control::Config::new(
|
let controller_config = client_core::client::real_messages_control::Config::new(
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
@@ -134,7 +128,6 @@ impl NymClient {
|
|||||||
mix_sender,
|
mix_sender,
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
shutdown,
|
|
||||||
)
|
)
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
@@ -146,7 +139,6 @@ impl NymClient {
|
|||||||
query_receiver: ReceivedBufferRequestReceiver,
|
query_receiver: ReceivedBufferRequestReceiver,
|
||||||
mixnet_receiver: MixnetMessageReceiver,
|
mixnet_receiver: MixnetMessageReceiver,
|
||||||
reply_key_storage: ReplyKeyStorage,
|
reply_key_storage: ReplyKeyStorage,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting received messages buffer controller...");
|
info!("Starting received messages buffer controller...");
|
||||||
ReceivedMessagesBufferController::new(
|
ReceivedMessagesBufferController::new(
|
||||||
@@ -154,7 +146,6 @@ impl NymClient {
|
|||||||
query_receiver,
|
query_receiver,
|
||||||
mixnet_receiver,
|
mixnet_receiver,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
shutdown,
|
|
||||||
)
|
)
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
@@ -163,7 +154,6 @@ impl NymClient {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mixnet_message_sender: MixnetMessageSender,
|
mixnet_message_sender: MixnetMessageSender,
|
||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> GatewayClient {
|
) -> GatewayClient {
|
||||||
let gateway_id = self.config.get_base().get_gateway_id();
|
let gateway_id = self.config.get_base().get_gateway_id();
|
||||||
if gateway_id.is_empty() {
|
if gateway_id.is_empty() {
|
||||||
@@ -191,6 +181,8 @@ impl NymClient {
|
|||||||
let bandwidth_controller = BandwidthController::new(
|
let bandwidth_controller = BandwidthController::new(
|
||||||
credential_storage::initialise_storage(self.config.get_base().get_database_path())
|
credential_storage::initialise_storage(self.config.get_base().get_database_path())
|
||||||
.await,
|
.await,
|
||||||
|
self.config.get_base().get_eth_endpoint(),
|
||||||
|
self.config.get_base().get_eth_private_key(),
|
||||||
)
|
)
|
||||||
.expect("Could not create bandwidth controller");
|
.expect("Could not create bandwidth controller");
|
||||||
|
|
||||||
@@ -204,12 +196,11 @@ impl NymClient {
|
|||||||
ack_sender,
|
ack_sender,
|
||||||
self.config.get_base().get_gateway_response_timeout(),
|
self.config.get_base().get_gateway_response_timeout(),
|
||||||
Some(bandwidth_controller),
|
Some(bandwidth_controller),
|
||||||
Some(shutdown),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
gateway_client
|
if self.config.get_base().get_disabled_credentials_mode() {
|
||||||
.set_disabled_credentials_mode(self.config.get_base().get_disabled_credentials_mode());
|
gateway_client.set_disabled_credentials_mode(true)
|
||||||
|
}
|
||||||
gateway_client
|
gateway_client
|
||||||
.authenticate_and_start()
|
.authenticate_and_start()
|
||||||
.await
|
.await
|
||||||
@@ -220,11 +211,7 @@ impl NymClient {
|
|||||||
|
|
||||||
// future responsible for periodically polling directory server and updating
|
// future responsible for periodically polling directory server and updating
|
||||||
// the current global view of topology
|
// the current global view of topology
|
||||||
async fn start_topology_refresher(
|
async fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||||
&mut self,
|
|
||||||
topology_accessor: TopologyAccessor,
|
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
|
||||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||||
self.config.get_base().get_validator_api_endpoints(),
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
self.config.get_base().get_topology_refresh_rate(),
|
self.config.get_base().get_topology_refresh_rate(),
|
||||||
@@ -246,7 +233,7 @@ impl NymClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("Starting topology refresher...");
|
info!("Starting topology refresher...");
|
||||||
topology_refresher.start(shutdown);
|
topology_refresher.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
||||||
@@ -257,17 +244,15 @@ impl NymClient {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mix_rx: BatchMixMessageReceiver,
|
mix_rx: BatchMixMessageReceiver,
|
||||||
gateway_client: GatewayClient,
|
gateway_client: GatewayClient,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting mix traffic controller...");
|
info!("Starting mix traffic controller...");
|
||||||
MixTrafficController::new(mix_rx, gateway_client, shutdown).start();
|
MixTrafficController::new(mix_rx, gateway_client).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_socks5_listener(
|
fn start_socks5_listener(
|
||||||
&self,
|
&self,
|
||||||
buffer_requester: ReceivedBufferRequestSender,
|
buffer_requester: ReceivedBufferRequestSender,
|
||||||
msg_input: InputMessageSender,
|
msg_input: InputMessageSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting socks5 listener...");
|
info!("Starting socks5 listener...");
|
||||||
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||||
@@ -279,57 +264,43 @@ impl NymClient {
|
|||||||
authenticator,
|
authenticator,
|
||||||
self.config.get_provider_mix_address(),
|
self.config.get_provider_mix_address(),
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
shutdown,
|
|
||||||
);
|
);
|
||||||
tokio::spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await });
|
tokio::spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// blocking version of `start` method. Will run forever (or until SIGINT is sent)
|
/// blocking version of `start` method. Will run forever (or until SIGINT is sent)
|
||||||
pub async fn run_forever(&mut self) {
|
pub async fn run_forever(&mut self) {
|
||||||
let mut shutdown = self.start().await;
|
self.start().await;
|
||||||
wait_for_signal().await;
|
if let Err(e) = tokio::signal::ctrl_c().await {
|
||||||
|
error!(
|
||||||
|
"There was an error while capturing SIGINT - {:?}. We will terminate regardless",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
log::info!("Sending shutdown");
|
println!(
|
||||||
client_core::client::SHUTDOWN_HAS_BEEN_SIGNALLED.store(true, Ordering::Relaxed);
|
"Received SIGINT - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
|
||||||
shutdown.signal_shutdown().ok();
|
);
|
||||||
|
|
||||||
log::info!("Waiting for tasks to finish... (Press ctrl-c to force)");
|
|
||||||
shutdown.wait_for_shutdown().await;
|
|
||||||
|
|
||||||
log::info!("Stopping nym-socks5-client");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variant of `run_forever` that listends for remote control messages
|
// Variant of `run_forever` that listends for remote control messages
|
||||||
pub async fn run_and_listen(&mut self, mut receiver: Socks5ControlMessageReceiver) {
|
pub async fn run_and_listen(&mut self, mut receiver: Socks5ControlMessageReceiver) {
|
||||||
let mut shutdown = self.start().await;
|
self.start().await;
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
message = receiver.next() => {
|
message = receiver.next() => {
|
||||||
log::debug!("Received message: {:?}", message);
|
log::debug!("Received message: {:?}", message);
|
||||||
match message {
|
match message {
|
||||||
Some(Socks5ControlMessage::Stop) => {
|
Some(Socks5ControlMessage::Stop) => {
|
||||||
log::info!("Received stop message");
|
log::info!("Shutting down");
|
||||||
}
|
log::info!("Graceful shutdown of tasks not yet implemented, you might see (harmless) panics until then");
|
||||||
None => {
|
|
||||||
log::info!("Channel closed, stopping");
|
|
||||||
}
|
}
|
||||||
|
None => log::debug!("None"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = tokio::signal::ctrl_c() => {
|
|
||||||
log::info!("Received SIGINT");
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Sending shutdown");
|
|
||||||
client_core::client::SHUTDOWN_HAS_BEEN_SIGNALLED.store(true, Ordering::Relaxed);
|
|
||||||
shutdown.signal_shutdown().ok();
|
|
||||||
|
|
||||||
log::info!("Waiting for tasks to finish... (Press ctrl-c to force)");
|
|
||||||
shutdown.wait_for_shutdown().await;
|
|
||||||
|
|
||||||
log::info!("Stopping nym-socks5-client");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(&mut self) -> ShutdownNotifier {
|
pub async fn start(&mut self) {
|
||||||
info!("Starting nym client");
|
info!("Starting nym client");
|
||||||
// channels for inter-component communication
|
// channels for inter-component communication
|
||||||
// TODO: make the channels be internally created by the relevant components
|
// TODO: make the channels be internally created by the relevant components
|
||||||
@@ -359,52 +330,33 @@ impl NymClient {
|
|||||||
ReplyKeyStorage::load(self.config.get_base().get_reply_encryption_key_store_path())
|
ReplyKeyStorage::load(self.config.get_base().get_reply_encryption_key_store_path())
|
||||||
.expect("Failed to load reply key storage!");
|
.expect("Failed to load reply key storage!");
|
||||||
|
|
||||||
// Shutdown notifier for signalling tasks to stop
|
|
||||||
let shutdown = ShutdownNotifier::default();
|
|
||||||
|
|
||||||
// the components are started in very specific order. Unless you know what you are doing,
|
// the components are started in very specific order. Unless you know what you are doing,
|
||||||
// do not change that.
|
// do not change that.
|
||||||
self.start_topology_refresher(shared_topology_accessor.clone(), shutdown.subscribe())
|
self.start_topology_refresher(shared_topology_accessor.clone())
|
||||||
.await;
|
.await;
|
||||||
self.start_received_messages_buffer_controller(
|
self.start_received_messages_buffer_controller(
|
||||||
received_buffer_request_receiver,
|
received_buffer_request_receiver,
|
||||||
mixnet_messages_receiver,
|
mixnet_messages_receiver,
|
||||||
reply_key_storage.clone(),
|
reply_key_storage.clone(),
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_client = self
|
let gateway_client = self
|
||||||
.start_gateway_client(mixnet_messages_sender, ack_sender, shutdown.subscribe())
|
.start_gateway_client(mixnet_messages_sender, ack_sender)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
self.start_mix_traffic_controller(
|
self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client);
|
||||||
sphinx_message_receiver,
|
|
||||||
gateway_client,
|
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
|
||||||
self.start_real_traffic_controller(
|
self.start_real_traffic_controller(
|
||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
ack_receiver,
|
ack_receiver,
|
||||||
input_receiver,
|
input_receiver,
|
||||||
sphinx_message_sender.clone(),
|
sphinx_message_sender.clone(),
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
self.start_cover_traffic_stream(
|
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||||
shared_topology_accessor,
|
self.start_socks5_listener(received_buffer_request_sender, input_sender);
|
||||||
sphinx_message_sender,
|
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
|
||||||
self.start_socks5_listener(
|
|
||||||
received_buffer_request_sender,
|
|
||||||
input_sender,
|
|
||||||
shutdown.subscribe(),
|
|
||||||
);
|
|
||||||
|
|
||||||
info!("Client startup finished!");
|
info!("Client startup finished!");
|
||||||
info!("The address of this client is: {}", self.as_mix_recipient());
|
info!("The address of this client is: {}", self.as_mix_recipient());
|
||||||
|
|
||||||
shutdown
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use client_core::{config::GatewayEndpoint, error::ClientCoreError};
|
use client_core::config::GatewayEndpoint;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -10,6 +10,9 @@ use crate::{
|
|||||||
commands::{override_config, OverrideConfig},
|
commands::{override_config, OverrideConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
#[derive(Args, Clone)]
|
||||||
pub(crate) struct Init {
|
pub(crate) struct Init {
|
||||||
/// Id of the nym-mixnet-client we want to create config for.
|
/// Id of the nym-mixnet-client we want to create config for.
|
||||||
@@ -43,10 +46,29 @@ pub(crate) struct Init {
|
|||||||
fastmode: bool,
|
fastmode: bool,
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
/// with bandwidth credential requirement.
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
#[cfg(feature = "coconut")]
|
/// --eth-private_key don't need to be set.
|
||||||
#[clap(long)]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
enabled_credentials_mode: bool,
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_ENDPOINT))
|
||||||
|
)]
|
||||||
|
eth_endpoint: String,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead")
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_PRIVATE_KEY))
|
||||||
|
)]
|
||||||
|
eth_private_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Init> for OverrideConfig {
|
impl From<Init> for OverrideConfig {
|
||||||
@@ -55,8 +77,15 @@ impl From<Init> for OverrideConfig {
|
|||||||
validators: init_config.validators,
|
validators: init_config.validators,
|
||||||
port: init_config.port,
|
port: init_config.port,
|
||||||
fastmode: init_config.fastmode,
|
fastmode: init_config.fastmode,
|
||||||
#[cfg(feature = "coconut")]
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Some(init_config.eth_private_key),
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Some(init_config.eth_endpoint),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,12 +121,7 @@ pub(crate) async fn execute(args: &Init) {
|
|||||||
let override_config_fields = OverrideConfig::from(args.clone());
|
let override_config_fields = OverrideConfig::from(args.clone());
|
||||||
config = override_config(config, override_config_fields);
|
config = override_config(config, override_config_fields);
|
||||||
|
|
||||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config)
|
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| {
|
|
||||||
eprintln!("Failed to setup gateway\nError: {err}");
|
|
||||||
std::process::exit(1)
|
|
||||||
});
|
|
||||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||||
|
|
||||||
let config_save_location = config.get_config_file_save_location();
|
let config_save_location = config.get_config_file_save_location();
|
||||||
@@ -115,10 +139,7 @@ pub(crate) async fn execute(args: &Init) {
|
|||||||
);
|
);
|
||||||
println!("Client configuration completed.");
|
println!("Client configuration completed.");
|
||||||
|
|
||||||
client_core::init::show_address(config.get_base()).unwrap_or_else(|err| {
|
client_core::init::show_address(config.get_base());
|
||||||
eprintln!("Failed to show address\nError: {err}");
|
|
||||||
std::process::exit(1)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_gateway(
|
async fn setup_gateway(
|
||||||
@@ -126,7 +147,7 @@ async fn setup_gateway(
|
|||||||
register: bool,
|
register: bool,
|
||||||
user_chosen_gateway_id: Option<&str>,
|
user_chosen_gateway_id: Option<&str>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> Result<GatewayEndpoint, ClientCoreError> {
|
) -> GatewayEndpoint {
|
||||||
if register {
|
if register {
|
||||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||||
// the chosen one if it's among the available ones.
|
// the chosen one if it's among the available ones.
|
||||||
@@ -135,16 +156,16 @@ async fn setup_gateway(
|
|||||||
config.get_base().get_validator_api_endpoints(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
user_chosen_gateway_id,
|
user_chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
log::debug!("Querying gateway gives: {}", gateway);
|
||||||
|
|
||||||
// Registering with gateway by setting up and writing shared keys to disk
|
// Registering with gateway by setting up and writing shared keys to disk
|
||||||
log::trace!("Registering gateway");
|
log::trace!("Registering gateway");
|
||||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||||
.await?;
|
.await;
|
||||||
println!("Saved all generated keys");
|
println!("Saved all generated keys");
|
||||||
|
|
||||||
Ok(gateway.into())
|
gateway.into()
|
||||||
} else if user_chosen_gateway_id.is_some() {
|
} else if user_chosen_gateway_id.is_some() {
|
||||||
// Just set the config, don't register or create any keys
|
// Just set the config, don't register or create any keys
|
||||||
// This assumes that the user knows what they are doing, and that the existing keys are
|
// This assumes that the user knows what they are doing, and that the existing keys are
|
||||||
@@ -154,21 +175,22 @@ async fn setup_gateway(
|
|||||||
config.get_base().get_validator_api_endpoints(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
user_chosen_gateway_id,
|
user_chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
log::debug!("Querying gateway gives: {}", gateway);
|
||||||
Ok(gateway.into())
|
gateway.into()
|
||||||
} else {
|
} else {
|
||||||
println!("Not registering gateway, will reuse existing config and keys");
|
println!("Not registering gateway, will reuse existing config and keys");
|
||||||
let existing_config = Config::load_from_file(Some(id)).map_err(|err| {
|
match Config::load_from_file(Some(id)) {
|
||||||
log::error!(
|
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
|
||||||
"Unable to configure gateway: {err}. \n
|
Err(err) => {
|
||||||
Seems like the client was already initialized but it was not possible to read \
|
panic!(
|
||||||
the existing configuration file. \n
|
"Unable to configure gateway: {err}. \n
|
||||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
Seems like the client was already initialized but it was not possible to read \
|
||||||
removing the existing configuration and starting over."
|
the existing configuration file. \n
|
||||||
);
|
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||||
ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err)
|
removing the existing configuration and starting over."
|
||||||
})?;
|
)
|
||||||
Ok(existing_config.get_base().get_gateway_endpoint().clone())
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,21 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use clap::CommandFactory;
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use completions::{fig_generate, ArgShell};
|
use network_defaults::DEFAULT_NETWORK;
|
||||||
use config::parse_validators;
|
use url::Url;
|
||||||
|
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
||||||
|
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001";
|
||||||
|
|
||||||
fn long_version() -> String {
|
fn long_version() -> String {
|
||||||
format!(
|
format!(
|
||||||
r#"
|
r#"
|
||||||
@@ -22,6 +28,7 @@ fn long_version() -> String {
|
|||||||
{:<20}{}
|
{:<20}{}
|
||||||
{:<20}{}
|
{:<20}{}
|
||||||
{:<20}{}
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
"#,
|
"#,
|
||||||
"Build Timestamp:",
|
"Build Timestamp:",
|
||||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
@@ -39,6 +46,8 @@ fn long_version() -> String {
|
|||||||
env!("VERGEN_RUSTC_CHANNEL"),
|
env!("VERGEN_RUSTC_CHANNEL"),
|
||||||
"cargo Profile:",
|
"cargo Profile:",
|
||||||
env!("VERGEN_CARGO_PROFILE"),
|
env!("VERGEN_CARGO_PROFILE"),
|
||||||
|
"Network:",
|
||||||
|
DEFAULT_NETWORK
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +58,6 @@ fn long_version_static() -> &'static str {
|
|||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
||||||
pub(crate) struct Cli {
|
pub(crate) struct Cli {
|
||||||
/// Path pointing to an env file that configures the client.
|
|
||||||
#[clap(long)]
|
|
||||||
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
}
|
}
|
||||||
@@ -65,12 +70,6 @@ pub(crate) enum Commands {
|
|||||||
Run(run::Run),
|
Run(run::Run),
|
||||||
/// Try to upgrade the client
|
/// Try to upgrade the client
|
||||||
Upgrade(upgrade::Upgrade),
|
Upgrade(upgrade::Upgrade),
|
||||||
|
|
||||||
/// Generate shell completions
|
|
||||||
Completions(ArgShell),
|
|
||||||
|
|
||||||
/// Generate Fig specification
|
|
||||||
GenerateFigSpec,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration that can be overridden.
|
// Configuration that can be overridden.
|
||||||
@@ -79,42 +78,67 @@ pub(crate) struct OverrideConfig {
|
|||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
fastmode: bool,
|
fastmode: bool,
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
enabled_credentials_mode: bool,
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Cli) {
|
pub(crate) async fn execute(args: &Cli) {
|
||||||
let bin_name = "nym-socks5-client";
|
|
||||||
|
|
||||||
match &args.command {
|
match &args.command {
|
||||||
Commands::Init(m) => init::execute(m).await,
|
Commands::Init(m) => init::execute(m).await,
|
||||||
Commands::Run(m) => run::execute(m).await,
|
Commands::Run(m) => run::execute(m).await,
|
||||||
Commands::Upgrade(m) => upgrade::execute(m),
|
Commands::Upgrade(m) => upgrade::execute(m),
|
||||||
Commands::Completions(s) => s.generate(&mut Cli::into_app(), bin_name),
|
|
||||||
Commands::GenerateFigSpec => fig_generate(&mut Cli::into_app(), bin_name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
|
raw.split(',')
|
||||||
|
.map(|raw_validator| {
|
||||||
|
raw_validator
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("one of the provided validator api urls is invalid")
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
||||||
if let Some(raw_validators) = args.validators {
|
if let Some(raw_validators) = args.validators {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_validator_apis(parse_validators(&raw_validators));
|
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||||
} else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) {
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validator_apis(parse_validators(&raw_validators));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(port) = args.port {
|
if let Some(port) = args.port {
|
||||||
config = config.with_port(port);
|
config = config.with_port(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
{
|
{
|
||||||
if args.enabled_credentials_mode {
|
if args.enabled_credentials_mode {
|
||||||
config.get_base_mut().with_disabled_credentials(false)
|
config.get_base_mut().with_disabled_credentials(false)
|
||||||
}
|
}
|
||||||
|
if let Some(eth_endpoint) = args.eth_endpoint {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
}
|
||||||
|
if let Some(eth_private_key) = args.eth_private_key {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.fastmode {
|
if args.fastmode {
|
||||||
|
|||||||
@@ -39,10 +39,23 @@ pub(crate) struct Run {
|
|||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
/// with bandwidth credential requirement.
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
#[cfg(feature = "coconut")]
|
/// --eth-private-key don't need to be set.
|
||||||
#[clap(long)]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
enabled_credentials_mode: bool,
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Run> for OverrideConfig {
|
impl From<Run> for OverrideConfig {
|
||||||
@@ -52,8 +65,14 @@ impl From<Run> for OverrideConfig {
|
|||||||
port: run_config.port,
|
port: run_config.port,
|
||||||
fastmode: false,
|
fastmode: false,
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: run_config.eth_private_key,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: run_config.eth_endpoint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
|
|
||||||
use config::NymConfig;
|
use config::{defaults::default_api_endpoints, NymConfig};
|
||||||
use version_checker::Version;
|
use version_checker::Version;
|
||||||
|
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
@@ -102,7 +102,16 @@ fn minor_0_12_upgrade(
|
|||||||
Version::new(0, 12, 0)
|
Version::new(0, 12, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
print_start_upgrade(config_version, &to_version);
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Setting validator API endpoints to {:?}",
|
||||||
|
default_api_endpoints()
|
||||||
|
);
|
||||||
|
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(default_api_endpoints());
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
@@ -110,7 +119,7 @@ fn minor_0_12_upgrade(
|
|||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
config.save_to_file(None).unwrap_or_else(|err| {
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||||
print_failed_upgrade(config_version, &to_version);
|
print_failed_upgrade(&config_version, &to_version);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
// This is only used as we reach into the init functions in nym-connect. We need to refactor the
|
||||||
|
// init functions so that nym-connect can just call the same init function as the regular socks5
|
||||||
|
// client.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub mod commands;
|
||||||
pub mod socks;
|
pub mod socks;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{crate_version, Parser};
|
use clap::{crate_version, Parser};
|
||||||
use network_defaults::setup_env;
|
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
mod commands;
|
mod commands;
|
||||||
@@ -10,11 +9,11 @@ pub mod socks;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
dotenv::dotenv().ok();
|
||||||
setup_logging();
|
setup_logging();
|
||||||
println!("{}", banner());
|
println!("{}", banner());
|
||||||
|
|
||||||
let args = commands::Cli::parse();
|
let args = commands::Cli::parse();
|
||||||
setup_env(args.config_env_file.clone());
|
|
||||||
commands::execute(&args).await;
|
commands::execute(&args).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ use socks5_requests::{ConnectionId, Message, RemoteAddress, Request};
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||||
use tokio::{self, net::TcpStream};
|
use tokio::{self, net::TcpStream};
|
||||||
|
|
||||||
@@ -141,7 +140,6 @@ pub(crate) struct SocksClient {
|
|||||||
service_provider: Recipient,
|
service_provider: Recipient,
|
||||||
self_address: Recipient,
|
self_address: Recipient,
|
||||||
started_proxy: bool,
|
started_proxy: bool,
|
||||||
shutdown_listener: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SocksClient {
|
impl Drop for SocksClient {
|
||||||
@@ -165,7 +163,6 @@ impl SocksClient {
|
|||||||
service_provider: Recipient,
|
service_provider: Recipient,
|
||||||
controller_sender: ControllerSender,
|
controller_sender: ControllerSender,
|
||||||
self_address: Recipient,
|
self_address: Recipient,
|
||||||
shutdown_listener: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let connection_id = Self::generate_random();
|
let connection_id = Self::generate_random();
|
||||||
SocksClient {
|
SocksClient {
|
||||||
@@ -179,7 +176,6 @@ impl SocksClient {
|
|||||||
service_provider,
|
service_provider,
|
||||||
self_address,
|
self_address,
|
||||||
started_proxy: false,
|
started_proxy: false,
|
||||||
shutdown_listener,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +250,6 @@ impl SocksClient {
|
|||||||
conn_receiver,
|
conn_receiver,
|
||||||
input_sender,
|
input_sender,
|
||||||
connection_id,
|
connection_id,
|
||||||
self.shutdown_listener.clone(),
|
|
||||||
)
|
)
|
||||||
.run(move |conn_id, read_data, socket_closed| {
|
.run(move |conn_id, read_data, socket_closed| {
|
||||||
let provider_request = Request::new_send(conn_id, read_data, socket_closed);
|
let provider_request = Request::new_send(conn_id, read_data, socket_closed);
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
|
use client_core::client::received_buffer::ReconstructedMessagesReceiver;
|
||||||
|
use client_core::client::received_buffer::{ReceivedBufferMessage, ReceivedBufferRequestSender};
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use client_core::client::received_buffer::ReconstructedMessagesReceiver;
|
|
||||||
use client_core::client::received_buffer::{ReceivedBufferMessage, ReceivedBufferRequestSender};
|
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
use nymsphinx::receiver::ReconstructedMessage;
|
||||||
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
|
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
|
||||||
use socks5_requests::Message;
|
use socks5_requests::Response;
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
pub(crate) struct MixnetResponseListener {
|
pub(crate) struct MixnetResponseListener {
|
||||||
buffer_requester: ReceivedBufferRequestSender,
|
buffer_requester: ReceivedBufferRequestSender,
|
||||||
mix_response_receiver: ReconstructedMessagesReceiver,
|
mix_response_receiver: ReconstructedMessagesReceiver,
|
||||||
controller_sender: ControllerSender,
|
controller_sender: ControllerSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for MixnetResponseListener {
|
impl Drop for MixnetResponseListener {
|
||||||
@@ -28,7 +25,6 @@ impl MixnetResponseListener {
|
|||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
buffer_requester: ReceivedBufferRequestSender,
|
buffer_requester: ReceivedBufferRequestSender,
|
||||||
controller_sender: ControllerSender,
|
controller_sender: ControllerSender,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (mix_response_sender, mix_response_receiver) = mpsc::unbounded();
|
let (mix_response_sender, mix_response_receiver) = mpsc::unbounded();
|
||||||
buffer_requester
|
buffer_requester
|
||||||
@@ -39,7 +35,6 @@ impl MixnetResponseListener {
|
|||||||
buffer_requester,
|
buffer_requester,
|
||||||
mix_response_receiver,
|
mix_response_receiver,
|
||||||
controller_sender,
|
controller_sender,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,23 +44,12 @@ impl MixnetResponseListener {
|
|||||||
warn!("this message had a surb - we didn't do anything with it");
|
warn!("this message had a surb - we didn't do anything with it");
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = match Message::try_from_bytes(&raw_message) {
|
let response = match Response::try_from_bytes(&raw_message) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("failed to parse received response - {:?}", err);
|
warn!("failed to parse received response - {:?}", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(Message::Request(_)) => {
|
Ok(data) => data,
|
||||||
warn!("unexpected request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Ok(Message::Response(data)) => data,
|
|
||||||
Ok(Message::NetworkRequesterResponse(r)) => {
|
|
||||||
error!(
|
|
||||||
"Network requester failed on connection id {} with error: {}",
|
|
||||||
r.connection_id, r.network_requester_error
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.controller_sender
|
self.controller_sender
|
||||||
@@ -78,25 +62,11 @@ impl MixnetResponseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn run(&mut self) {
|
pub(crate) async fn run(&mut self) {
|
||||||
while !self.shutdown.is_shutdown() {
|
while let Some(received_responses) = self.mix_response_receiver.next().await {
|
||||||
tokio::select! {
|
for reconstructed_message in received_responses {
|
||||||
received_responses = self.mix_response_receiver.next() => match received_responses {
|
self.on_message(reconstructed_message).await;
|
||||||
Some(received_responses) => {
|
|
||||||
for reconstructed_message in received_responses {
|
|
||||||
self.on_message(reconstructed_message).await;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
log::trace!("MixnetResponseListener: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log::trace!("MixnetResponseListener: Received shutdown");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(self.shutdown.is_shutdown_poll());
|
error!("We should never see this message");
|
||||||
log::debug!("MixnetResponseListener: Exiting");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use log::*;
|
|||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use proxy_helpers::connection_controller::Controller;
|
use proxy_helpers::connection_controller::Controller;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use task::ShutdownListener;
|
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
/// A Socks5 server that listens for connections.
|
/// A Socks5 server that listens for connections.
|
||||||
@@ -20,7 +19,6 @@ pub struct SphinxSocksServer {
|
|||||||
listening_address: SocketAddr,
|
listening_address: SocketAddr,
|
||||||
service_provider: Recipient,
|
service_provider: Recipient,
|
||||||
self_address: Recipient,
|
self_address: Recipient,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SphinxSocksServer {
|
impl SphinxSocksServer {
|
||||||
@@ -30,7 +28,6 @@ impl SphinxSocksServer {
|
|||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
service_provider: Recipient,
|
service_provider: Recipient,
|
||||||
self_address: Recipient,
|
self_address: Recipient,
|
||||||
shutdown: ShutdownListener,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
||||||
// just modify the config
|
// just modify the config
|
||||||
@@ -41,7 +38,6 @@ impl SphinxSocksServer {
|
|||||||
listening_address: format!("{}:{}", ip, port).parse().unwrap(),
|
listening_address: format!("{}:{}", ip, port).parse().unwrap(),
|
||||||
service_provider,
|
service_provider,
|
||||||
self_address,
|
self_address,
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,73 +52,62 @@ impl SphinxSocksServer {
|
|||||||
info!("Serving Connections...");
|
info!("Serving Connections...");
|
||||||
|
|
||||||
// controller for managing all active connections
|
// controller for managing all active connections
|
||||||
let (mut active_streams_controller, controller_sender) =
|
let (mut active_streams_controller, controller_sender) = Controller::new();
|
||||||
Controller::new(self.shutdown.clone());
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
active_streams_controller.run().await;
|
active_streams_controller.run().await;
|
||||||
});
|
});
|
||||||
|
|
||||||
// listener for mix messages
|
// listener for mix messages
|
||||||
let mut mixnet_response_listener = MixnetResponseListener::new(
|
let mut mixnet_response_listener =
|
||||||
buffer_requester,
|
MixnetResponseListener::new(buffer_requester, controller_sender.clone());
|
||||||
controller_sender.clone(),
|
|
||||||
self.shutdown.clone(),
|
|
||||||
);
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
mixnet_response_listener.run().await;
|
mixnet_response_listener.run().await;
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
if let Ok((stream, _remote)) = listener.accept().await {
|
||||||
Ok((stream, _remote)) = listener.accept() => {
|
// TODO Optimize this
|
||||||
// TODO Optimize this
|
let mut client = SocksClient::new(
|
||||||
let mut client = SocksClient::new(
|
stream,
|
||||||
stream,
|
self.authenticator.clone(),
|
||||||
self.authenticator.clone(),
|
input_sender.clone(),
|
||||||
input_sender.clone(),
|
self.service_provider,
|
||||||
self.service_provider,
|
controller_sender.clone(),
|
||||||
controller_sender.clone(),
|
self.self_address,
|
||||||
self.self_address,
|
);
|
||||||
self.shutdown.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
{
|
{
|
||||||
match client.run().await {
|
match client.run().await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("Error! {}", error);
|
error!("Error! {}", error);
|
||||||
let error_text = format!("{}", error);
|
let error_text = format!("{}", error);
|
||||||
|
|
||||||
let response: ResponseCode;
|
let response: ResponseCode;
|
||||||
|
|
||||||
if error_text.contains("Host") {
|
if error_text.contains("Host") {
|
||||||
response = ResponseCode::HostUnreachable;
|
response = ResponseCode::HostUnreachable;
|
||||||
} else if error_text.contains("Network") {
|
} else if error_text.contains("Network") {
|
||||||
response = ResponseCode::NetworkUnreachable;
|
response = ResponseCode::NetworkUnreachable;
|
||||||
} else if error_text.contains("ttl") {
|
} else if error_text.contains("ttl") {
|
||||||
response = ResponseCode::TtlExpired
|
response = ResponseCode::TtlExpired
|
||||||
} else {
|
} else {
|
||||||
response = ResponseCode::Failure
|
response = ResponseCode::Failure
|
||||||
}
|
|
||||||
|
|
||||||
if client.error(response).await.is_err() {
|
|
||||||
warn!("Failed to send error code");
|
|
||||||
};
|
|
||||||
if client.shutdown().await.is_err() {
|
|
||||||
warn!("Failed to shutdown TcpStream");
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// client gets dropped here
|
if client.error(response).await.is_err() {
|
||||||
}
|
warn!("Failed to send error code");
|
||||||
});
|
};
|
||||||
},
|
if client.shutdown().await.is_err() {
|
||||||
_ = self.shutdown.recv() => {
|
warn!("Failed to shutdown TcpStream");
|
||||||
log::trace!("SphinxSocksServer: Received shutdown");
|
};
|
||||||
log::debug!("SphinxSocksServer: Exiting");
|
}
|
||||||
return Ok(());
|
};
|
||||||
}
|
// client gets dropped here
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
16
|
15.0.1
|
||||||
@@ -31,12 +31,9 @@
|
|||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-mocha": "^10.0.3",
|
"eslint-plugin-mocha": "^10.0.3",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"expect": "^28.1.3",
|
|
||||||
"mocha": "^10.0.0",
|
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"typedoc": "^0.22.13",
|
"typedoc": "^0.22.13",
|
||||||
"ts-mocha": "^10.0.0",
|
"typescript": "^4.1.3"
|
||||||
"typescript": "^4.6.2"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cosmjs/cosmwasm-stargate": "^0.28.0",
|
"@cosmjs/cosmwasm-stargate": "^0.28.0",
|
||||||
|
|||||||
@@ -64,20 +64,23 @@ export default class ValidatorClient implements INymClient {
|
|||||||
|
|
||||||
readonly vestingContract: string;
|
readonly vestingContract: string;
|
||||||
|
|
||||||
readonly mainnetDenom = 'unym';
|
readonly mainnetDenom = "unym";
|
||||||
|
|
||||||
readonly mainnetPrefix = 'n';
|
readonly mainnetPrefix = "n";
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
client: SigningClient | QueryClient,
|
client: SigningClient | QueryClient,
|
||||||
prefix: string,
|
prefix: string,
|
||||||
mixnetContract: string,
|
mixnetContract: string,
|
||||||
vestingContract: string,
|
vestingContract: string
|
||||||
denom: string,
|
|
||||||
) {
|
) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.prefix = prefix;
|
this.prefix = prefix;
|
||||||
this.denom = `u${denom}`;
|
if (prefix == this.mainnetPrefix) {
|
||||||
|
this.denom = this.mainnetDenom;
|
||||||
|
} else {
|
||||||
|
this.denom = `u${prefix}`;
|
||||||
|
}
|
||||||
|
|
||||||
this.mixnetContract = mixnetContract;
|
this.mixnetContract = mixnetContract;
|
||||||
this.vestingContract = vestingContract;
|
this.vestingContract = vestingContract;
|
||||||
@@ -90,12 +93,11 @@ export default class ValidatorClient implements INymClient {
|
|||||||
prefix: string,
|
prefix: string,
|
||||||
mixnetContract: string,
|
mixnetContract: string,
|
||||||
vestingContract: string,
|
vestingContract: string,
|
||||||
denom: string,
|
|
||||||
): Promise<ValidatorClient> {
|
): Promise<ValidatorClient> {
|
||||||
const wallet = await ValidatorClient.buildWallet(mnemonic, prefix);
|
const wallet = await ValidatorClient.buildWallet(mnemonic, prefix);
|
||||||
|
|
||||||
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, validatorApiUrl, prefix, denom);
|
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, validatorApiUrl, prefix);
|
||||||
return new ValidatorClient(signingClient, prefix, mixnetContract, vestingContract, denom);
|
return new ValidatorClient(signingClient, prefix, mixnetContract, vestingContract);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async connectForQuery(
|
static async connectForQuery(
|
||||||
@@ -104,10 +106,9 @@ export default class ValidatorClient implements INymClient {
|
|||||||
prefix: string,
|
prefix: string,
|
||||||
mixnetContract: string,
|
mixnetContract: string,
|
||||||
vestingContract: string,
|
vestingContract: string,
|
||||||
denom: string,
|
|
||||||
): Promise<ValidatorClient> {
|
): Promise<ValidatorClient> {
|
||||||
const queryClient = await QueryClient.connectWithNym(nymdUrl, validatorApiUrl);
|
const queryClient = await QueryClient.connectWithNym(nymdUrl, validatorApiUrl);
|
||||||
return new ValidatorClient(queryClient, prefix, mixnetContract, vestingContract, denom);
|
return new ValidatorClient(queryClient, prefix, mixnetContract, vestingContract);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get address(): string {
|
public get address(): string {
|
||||||
@@ -456,4 +457,4 @@ export default class ValidatorClient implements INymClient {
|
|||||||
this.assertSigning();
|
this.assertSigning();
|
||||||
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,12 +221,10 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
|||||||
nymdUrl: string,
|
nymdUrl: string,
|
||||||
validatorApiUrl: string,
|
validatorApiUrl: string,
|
||||||
prefix: string,
|
prefix: string,
|
||||||
denom: string,
|
|
||||||
): Promise<SigningClient> {
|
): Promise<SigningClient> {
|
||||||
const [{ address }] = await wallet.getAccounts();
|
const [{ address }] = await wallet.getAccounts();
|
||||||
const signerOptions: SigningCosmWasmClientOptions = {
|
const signerOptions: SigningCosmWasmClientOptions = {
|
||||||
prefix,
|
gasPrice: nymGasPrice(prefix),
|
||||||
gasPrice: nymGasPrice(denom),
|
|
||||||
};
|
};
|
||||||
const tmClient = await Tendermint34Client.connect(nymdUrl);
|
const tmClient = await Tendermint34Client.connect(nymdUrl);
|
||||||
return new SigningClient(address, validatorApiUrl, tmClient, wallet, signerOptions);
|
return new SigningClient(address, validatorApiUrl, tmClient, wallet, signerOptions);
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ const mainnetDenom = 'nym';
|
|||||||
export function nymGasPrice(prefix: string): GasPrice {
|
export function nymGasPrice(prefix: string): GasPrice {
|
||||||
if (typeof prefix === 'string') {
|
if (typeof prefix === 'string') {
|
||||||
if (prefix === mainnetPrefix) {
|
if (prefix === mainnetPrefix) {
|
||||||
return GasPrice.fromString(`0.025u${mainnetDenom}`);
|
prefix = mainnetDenom;
|
||||||
}
|
}
|
||||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
throw new Error(`${prefix} is not of type string`);
|
throw new Error(`${prefix} is not of type string`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import ValidatorClient from '../../dist';
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe('Query: balances', () => {
|
|
||||||
it('can query for an account balance', async () => {
|
|
||||||
const client = await ValidatorClient.connectForQuery(
|
|
||||||
'https://rpc.nymtech.net/', 'https://validator.nymtech.net/api/', 'n', 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g', 'n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw', 'nym');
|
|
||||||
const balance = await client.getBalance('n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy');
|
|
||||||
expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
|
||||||
}).timeout(5000);
|
|
||||||
})
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import ValidatorClient from '../../dist';
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
// TODO: implement for QA with .env for mnemonics
|
|
||||||
// describe('Sign: send', () => {
|
|
||||||
// it('can send tokens', async () => {
|
|
||||||
// const client = await ValidatorClient.connect(
|
|
||||||
// '<ADD MNEMONIC HERE>',
|
|
||||||
// 'https://rpc.nyx.nodes.guru/', 'https://validator.nymtech.net/api/', 'n', 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g', 'n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw', 'nym');
|
|
||||||
// await client.send('<ADD ADDRESS HERE>')
|
|
||||||
// const balance = await client.getBalance('n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy');
|
|
||||||
// expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
|
||||||
// }).timeout(5000);
|
|
||||||
// })
|
|
||||||
@@ -5,8 +5,7 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist"
|
||||||
"skipLibCheck": true
|
|
||||||
},
|
},
|
||||||
"typedocOptions": {
|
"typedocOptions": {
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client-wasm"
|
name = "nym-client-wasm"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@@ -32,7 +32,7 @@ credentials = { path = "../../common/credentials", optional = true }
|
|||||||
crypto = { path = "../../common/crypto" }
|
crypto = { path = "../../common/crypto" }
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nymsphinx = { path = "../../common/nymsphinx" }
|
||||||
topology = { path = "../../common/topology" }
|
topology = { path = "../../common/topology" }
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
|
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||||
wasm-utils = { path = "../../common/wasm-utils" }
|
wasm-utils = { path = "../../common/wasm-utils" }
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ This client is part of the [Nym](https://nymtech.net/docs) project. It's written
|
|||||||
## Security Status
|
## Security Status
|
||||||
|
|
||||||
From a security point of view, this module is not yet complete. Key missing features include, but are not limited to: cover traffic, sending packets with delay according to Poisson distribution.
|
From a security point of view, this module is not yet complete. Key missing features include, but are not limited to: cover traffic, sending packets with delay according to Poisson distribution.
|
||||||
|
|
||||||
They should be implemented soon. You can build your applications, but don't rely on it for strong anonymity yet if your application needs cover traffic.
|
They should be implemented soon. You can build your applications, but don't rely on it for strong anonymity yet if your application needs cover traffic.
|
||||||
|
|
||||||
## Using it
|
## Using it
|
||||||
@@ -38,6 +37,6 @@ To be clear, this is not something that most JS developers need to worry about,
|
|||||||
|
|
||||||
If you're a Nym platform developer who's made changes to the Rust (or JS) files and wants to re-publish the package to NPM, here's how you do it:
|
If you're a Nym platform developer who's made changes to the Rust (or JS) files and wants to re-publish the package to NPM, here's how you do it:
|
||||||
|
|
||||||
1. bump version numbers as necessary for SemVer
|
1. `wasm-pack build --scope nymproject` builds the wasm binaries into the `pkg` directory (not in source control)
|
||||||
2. `wasm-pack build --scope nymproject` builds the wasm binaries into the `pkg` directory (not in source control)
|
2. bump version numbers as necessary for SemVer
|
||||||
3. `cd pkg && npm publish --access=public` will publish your changed package to NPM
|
3. `wasm-pack publish --access=public` will publish your changed package to NPM
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NymClient,
|
NymClient,
|
||||||
set_panic_hook
|
set_panic_hook
|
||||||
} from "@nymproject/nym-client-wasm"
|
} from "@nymproject/nym-client-wasm"
|
||||||
|
|
||||||
// current limitation of rust-wasm for async stuff : (
|
// current limitation of rust-wasm for async stuff : (
|
||||||
@@ -25,7 +25,7 @@ async function main() {
|
|||||||
set_panic_hook();
|
set_panic_hook();
|
||||||
|
|
||||||
// validator server we will use to get topology from
|
// validator server we will use to get topology from
|
||||||
const validator = "https://validator.nymtech.net/api";
|
const validator = "https://sandbox-validator.nymtech.net/api"; //"http://localhost:8081";
|
||||||
|
|
||||||
client = new NymClient(validator);
|
client = new NymClient(validator);
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ async function sendMessageTo() {
|
|||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
function displaySend(message) {
|
function displaySend(message) {
|
||||||
let timestamp = new Date().toISOString().slice(11, 21);
|
let timestamp = new Date().toISOString().substr(11, 12);
|
||||||
|
|
||||||
let sendDiv = document.createElement("div")
|
let sendDiv = document.createElement("div")
|
||||||
let paragraph = document.createElement("p")
|
let paragraph = document.createElement("p")
|
||||||
@@ -90,11 +90,11 @@ function displayReceived(message) {
|
|||||||
const content = message.message
|
const content = message.message
|
||||||
const replySurb = message.replySurb
|
const replySurb = message.replySurb
|
||||||
|
|
||||||
let timestamp = new Date().toISOString().slice(11, 21);
|
let timestamp = new Date().toISOString().substr(11, 12);
|
||||||
let receivedDiv = document.createElement("div")
|
let receivedDiv = document.createElement("div")
|
||||||
let paragraph = document.createElement("p")
|
let paragraph = document.createElement("p")
|
||||||
paragraph.setAttribute('style', 'color: green')
|
paragraph.setAttribute('style', 'color: green')
|
||||||
let paragraphContent = document.createTextNode(timestamp + " received >>> " + content)
|
let paragraphContent = document.createTextNode(timestamp + " received >>> " + content + ((replySurb != null) ? "Reply SURB was attached here (but we can't do anything with it yet" : " (NO REPLY-SURB AVAILABLE)"))
|
||||||
paragraph.appendChild(paragraphContent)
|
paragraph.appendChild(paragraphContent)
|
||||||
receivedDiv.appendChild(paragraph)
|
receivedDiv.appendChild(paragraph)
|
||||||
document.getElementById("output").appendChild(receivedDiv)
|
document.getElementById("output").appendChild(receivedDiv)
|
||||||
|
|||||||
+25
-115
@@ -36,64 +36,6 @@
|
|||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/set-array": "^1.0.1",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/set-array": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/source-map": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/gen-mapping": "^0.3.0",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
|
||||||
"version": "1.4.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
|
||||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
|
||||||
"version": "0.3.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
|
|
||||||
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@@ -3330,14 +3272,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.15.0",
|
"version": "5.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz",
|
||||||
"integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==",
|
"integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^8.5.0",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
|
"source-map": "~0.7.2",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -3430,6 +3372,15 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/terser/node_modules/source-map": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/thunky": {
|
"node_modules/thunky": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
||||||
@@ -3877,55 +3828,6 @@
|
|||||||
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
|
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@jridgewell/gen-mapping": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@jridgewell/set-array": "^1.0.1",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@jridgewell/resolve-uri": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@jridgewell/set-array": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@jridgewell/source-map": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@jridgewell/gen-mapping": "^0.3.0",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@jridgewell/sourcemap-codec": {
|
|
||||||
"version": "1.4.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
|
||||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@jridgewell/trace-mapping": {
|
|
||||||
"version": "0.3.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
|
|
||||||
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@nodelib/fs.scandir": {
|
"@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@@ -6432,15 +6334,23 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "5.15.0",
|
"version": "5.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz",
|
||||||
"integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==",
|
"integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^8.5.0",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
|
"source-map": "~0.7.2",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terser-webpack-plugin": {
|
"terser-webpack-plugin": {
|
||||||
|
|||||||
@@ -34,6 +34,6 @@
|
|||||||
"webpack-dev-server": "^4.7.4"
|
"webpack-dev-server": "^4.7.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nymproject/nym-client-wasm": "1.0.0"
|
"@nymproject/nym-client-wasm": "file:../pkg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
mode: "development",
|
mode: "development",
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin({ patterns: ['index.html'] })
|
new CopyWebpackPlugin({patterns: ['index.html']})
|
||||||
],
|
],
|
||||||
experiments: { syncWebAssembly: true }
|
experiments: { asyncWebAssembly: true }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use rand::rngs::OsRng;
|
|||||||
use received_processor::ReceivedMessagesProcessor;
|
use received_processor::ReceivedMessagesProcessor;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use topology::{gateway, nym_topology_from_detailed, NymTopology};
|
use topology::{gateway, nym_topology_from_bonds, NymTopology};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
@@ -132,7 +132,9 @@ impl NymClient {
|
|||||||
bandwidth_controller,
|
bandwidth_controller,
|
||||||
);
|
);
|
||||||
|
|
||||||
gateway_client.set_disabled_credentials_mode(disabled_credentials_mode);
|
if disabled_credentials_mode {
|
||||||
|
gateway_client.set_disabled_credentials_mode(true)
|
||||||
|
}
|
||||||
|
|
||||||
gateway_client
|
gateway_client
|
||||||
.authenticate_and_start()
|
.authenticate_and_start()
|
||||||
@@ -197,6 +199,7 @@ impl NymClient {
|
|||||||
// don't bother with acks etc. for time being
|
// don't bother with acks etc. for time being
|
||||||
let prepared_fragment = message_preparer
|
let prepared_fragment = message_preparer
|
||||||
.prepare_chunk_for_sending(message_chunk, topology, &self.ack_key, &recipient)
|
.prepare_chunk_for_sending(message_chunk, topology, &self.ack_key, &recipient)
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
console_warn!("packet is going to have round trip time of {:?}, but we're not going to do anything for acks anyway ", prepared_fragment.total_delay);
|
console_warn!("packet is going to have round trip time of {:?}, but we're not going to do anything for acks anyway ", prepared_fragment.total_delay);
|
||||||
@@ -265,7 +268,7 @@ impl NymClient {
|
|||||||
Ok(gateways) => gateways,
|
Ok(gateways) => gateways,
|
||||||
};
|
};
|
||||||
|
|
||||||
let topology = nym_topology_from_detailed(mixnodes, gateways);
|
let topology = nym_topology_from_bonds(mixnodes, gateways);
|
||||||
let version = env!("CARGO_PKG_VERSION");
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
topology.filter_system_version(version)
|
topology.filter_system_version(version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,22 +10,23 @@ edition = "2021"
|
|||||||
# TODO: (for this and other crates), similarly to 'tokio', import only required "futures" modules rather than
|
# TODO: (for this and other crates), similarly to 'tokio', import only required "futures" modules rather than
|
||||||
# the entire crate
|
# the entire crate
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
json = "0.12.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||||
secp256k1 = { version = "0.20.3", optional = true }
|
secp256k1 = "0.20.3"
|
||||||
web3 = { version = "0.17.0", default-features = false, optional = true }
|
web3 = { version = "0.17.0", default-features = false }
|
||||||
async-trait = { version = "0.1.51" }
|
async-trait = { version = "0.1.51" }
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
coconut-interface = { path = "../../coconut-interface", optional = true }
|
|
||||||
credentials = { path = "../../credentials" }
|
credentials = { path = "../../credentials" }
|
||||||
crypto = { path = "../../crypto" }
|
crypto = { path = "../../crypto" }
|
||||||
gateway-requests = { path = "../../../gateway/gateway-requests" }
|
gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||||
network-defaults = { path = "../../network-defaults" }
|
|
||||||
nymsphinx = { path = "../../nymsphinx" }
|
nymsphinx = { path = "../../nymsphinx" }
|
||||||
pemstore = { path = "../../pemstore" }
|
pemstore = { path = "../../pemstore" }
|
||||||
|
coconut-interface = { path = "../../coconut-interface", optional = true }
|
||||||
|
network-defaults = { path = "../../network-defaults" }
|
||||||
validator-client = { path = "../validator-client", optional = true }
|
validator-client = { path = "../validator-client", optional = true }
|
||||||
|
|
||||||
[dependencies.tungstenite]
|
[dependencies.tungstenite]
|
||||||
@@ -37,19 +38,12 @@ default-features = false
|
|||||||
version = "1.19.1"
|
version = "1.19.1"
|
||||||
features = ["macros", "rt", "net", "sync", "time"]
|
features = ["macros", "rt", "net", "sync", "time"]
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
|
||||||
version = "0.1.9"
|
|
||||||
features = ["net", "sync", "time"]
|
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||||
version = "0.14"
|
version = "0.14"
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.credential-storage]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.credential-storage]
|
||||||
path = "../../credential-storage"
|
path = "../../credential-storage"
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.task]
|
|
||||||
path = "../../task"
|
|
||||||
|
|
||||||
# wasm-only dependencies
|
# wasm-only dependencies
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
@@ -79,5 +73,5 @@ features = ["js"]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"]
|
coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"]
|
||||||
wasm = []
|
wasm = ["web3/wasm", "web3/http", "web3/signing"]
|
||||||
default = ["web3/default", "secp256k1"]
|
default = ["web3/default"]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::GatewayClientError;
|
use crate::error::GatewayClientError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use crate::wasm_storage::Storage;
|
use crate::wasm_storage::Storage;
|
||||||
@@ -14,8 +15,6 @@ use crate::wasm_storage::StorageError;
|
|||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
|
||||||
use credential_storage::error::StorageError;
|
use credential_storage::error::StorageError;
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
|
||||||
use std::str::FromStr;
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(feature = "coconut")]
|
||||||
use {
|
use {
|
||||||
coconut_interface::Base58,
|
coconut_interface::Base58,
|
||||||
@@ -24,12 +23,65 @@ use {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use {
|
||||||
|
credentials::token::bandwidth::TokenCredential,
|
||||||
|
crypto::asymmetric::identity,
|
||||||
|
network_defaults::{
|
||||||
|
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE,
|
||||||
|
ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||||
|
ETH_ERC20_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
|
||||||
|
},
|
||||||
|
pemstore::traits::PemStorableKeyPair,
|
||||||
|
rand::rngs::OsRng,
|
||||||
|
secp256k1::SecretKey,
|
||||||
|
web3::{
|
||||||
|
contract::{Contract, Options},
|
||||||
|
ethabi::Token,
|
||||||
|
signing::{Key, SecretKeyRef},
|
||||||
|
transports::Http,
|
||||||
|
types::{Address, U256, U64},
|
||||||
|
Web3,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||||
|
Contract::from_json(
|
||||||
|
web3.eth(),
|
||||||
|
Address::from(ETH_CONTRACT_ADDRESS),
|
||||||
|
json::parse(ETH_JSON_ABI)
|
||||||
|
.expect("Invalid json abi")
|
||||||
|
.dump()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.expect("Invalid json abi")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn eth_erc20_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||||
|
Contract::from_json(
|
||||||
|
web3.eth(),
|
||||||
|
Address::from(ETH_ERC20_CONTRACT_ADDRESS),
|
||||||
|
json::parse(ETH_ERC20_JSON_ABI)
|
||||||
|
.expect("Invalid json abi")
|
||||||
|
.dump()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.expect("Invalid json abi")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BandwidthController<St: Storage> {
|
pub struct BandwidthController<St: Storage> {
|
||||||
#[allow(dead_code)]
|
|
||||||
storage: St,
|
storage: St,
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(feature = "coconut")]
|
||||||
validator_endpoints: Vec<url::Url>,
|
validator_endpoints: Vec<url::Url>,
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
contract: Contract<Http>,
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
erc20_contract: Contract<Http>,
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_private_key: SecretKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<St> BandwidthController<St>
|
impl<St> BandwidthController<St>
|
||||||
@@ -45,8 +97,60 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub fn new(storage: St) -> Result<Self, GatewayClientError> {
|
pub fn new(
|
||||||
Ok(BandwidthController { storage })
|
storage: St,
|
||||||
|
eth_endpoint: String,
|
||||||
|
eth_private_key: String,
|
||||||
|
) -> Result<Self, GatewayClientError> {
|
||||||
|
// Fail early, on invalid url
|
||||||
|
let transport =
|
||||||
|
Http::new(ð_endpoint).map_err(|_| GatewayClientError::InvalidURL(eth_endpoint))?;
|
||||||
|
let web3 = web3::Web3::new(transport);
|
||||||
|
// Fail early, on invalid abi
|
||||||
|
let contract = eth_contract(web3.clone());
|
||||||
|
let erc20_contract = eth_erc20_contract(web3);
|
||||||
|
let eth_private_key = secp256k1::SecretKey::from_str(ð_private_key)
|
||||||
|
.map_err(|_| GatewayClientError::InvalidEthereumPrivateKey)?;
|
||||||
|
|
||||||
|
Ok(BandwidthController {
|
||||||
|
storage,
|
||||||
|
contract,
|
||||||
|
erc20_contract,
|
||||||
|
eth_private_key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
async fn backup_keypair(&self, keypair: &identity::KeyPair) -> Result<(), GatewayClientError> {
|
||||||
|
self.storage
|
||||||
|
.insert_erc20_credential(
|
||||||
|
keypair.public_key().to_base58_string(),
|
||||||
|
keypair.private_key().to_base58_string(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
async fn restore_keypair(&self) -> Result<identity::KeyPair, GatewayClientError> {
|
||||||
|
let data = self.storage.get_next_erc20_credential().await?;
|
||||||
|
let public_key = identity::PublicKey::from_base58_string(data.public_key).unwrap();
|
||||||
|
let private_key = identity::PrivateKey::from_base58_string(data.private_key).unwrap();
|
||||||
|
|
||||||
|
Ok(identity::KeyPair::from_keys(private_key, public_key))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
async fn mark_keypair_as_spent(
|
||||||
|
&self,
|
||||||
|
keypair: &identity::KeyPair,
|
||||||
|
) -> Result<(), GatewayClientError> {
|
||||||
|
self.storage
|
||||||
|
.consume_erc20_credential(keypair.public_key().to_base58_string())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(feature = "coconut")]
|
||||||
@@ -75,4 +179,206 @@ where
|
|||||||
&verification_key,
|
&verification_key,
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub async fn prepare_token_credential(
|
||||||
|
&self,
|
||||||
|
gateway_identity: identity::PublicKey,
|
||||||
|
gateway_owner: String,
|
||||||
|
) -> Result<TokenCredential, GatewayClientError> {
|
||||||
|
let kp = match self.restore_keypair().await {
|
||||||
|
Ok(kp) => kp,
|
||||||
|
Err(_) => {
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let kp = identity::KeyPair::new(&mut rng);
|
||||||
|
self.backup_keypair(&kp).await?;
|
||||||
|
kp
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let verification_key = *kp.public_key();
|
||||||
|
let signed_verification_key = kp.private_key().sign(&verification_key.to_bytes());
|
||||||
|
self.buy_token_credential(verification_key, signed_verification_key, gateway_owner)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.mark_keypair_as_spent(&kp).await?;
|
||||||
|
|
||||||
|
let message: Vec<u8> = verification_key
|
||||||
|
.to_bytes()
|
||||||
|
.iter()
|
||||||
|
.chain(gateway_identity.to_bytes().iter())
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
|
let signature = kp.private_key().sign(&message);
|
||||||
|
|
||||||
|
Ok(TokenCredential::new(
|
||||||
|
verification_key,
|
||||||
|
gateway_identity,
|
||||||
|
BANDWIDTH_VALUE,
|
||||||
|
signature,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub async fn buy_token_credential(
|
||||||
|
&self,
|
||||||
|
verification_key: identity::PublicKey,
|
||||||
|
signed_verification_key: identity::Signature,
|
||||||
|
gateway_owner: String,
|
||||||
|
) -> Result<(), GatewayClientError> {
|
||||||
|
let confirmations = if cfg!(debug_assertions) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
ETH_MIN_BLOCK_DEPTH
|
||||||
|
};
|
||||||
|
// 15 seconds per confirmation block + 10 seconds of network overhead + 20 seconds of wait for kill
|
||||||
|
log::info!(
|
||||||
|
"Waiting for Ethereum transaction. This should take about {} seconds",
|
||||||
|
(confirmations + 1) * 15 + 30
|
||||||
|
);
|
||||||
|
let mut options = Options::default();
|
||||||
|
let estimation = self
|
||||||
|
.erc20_contract
|
||||||
|
.estimate_gas(
|
||||||
|
ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||||
|
(
|
||||||
|
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
|
||||||
|
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||||
|
),
|
||||||
|
SecretKeyRef::from(&self.eth_private_key).address(),
|
||||||
|
options.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
options.gas = Some(estimation);
|
||||||
|
log::info!("Calling ERC20 approve in 10 seconds with an estimated gas of {}. Kill the process if you want to abort", estimation);
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
|
||||||
|
log::error!(
|
||||||
|
"the timer has gone away while waiting for possible kill! - {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let recipt = self
|
||||||
|
.erc20_contract
|
||||||
|
.signed_call_with_confirmations(
|
||||||
|
ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||||
|
(
|
||||||
|
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
|
||||||
|
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||||
|
),
|
||||||
|
options,
|
||||||
|
1, // One confirmation is enough, as we'll be consuming the approved token next anyway
|
||||||
|
&self.eth_private_key,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
if Some(U64::from(0u64)) == recipt.status {
|
||||||
|
return Err(GatewayClientError::BurnTokenError(
|
||||||
|
web3::Error::InvalidResponse(format!(
|
||||||
|
"Approve transaction status is 0 (failure): {:?}",
|
||||||
|
recipt.logs,
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
log::info!(
|
||||||
|
"Approved {} tokens for bandwidth use on Ethereum",
|
||||||
|
TOKENS_TO_BURN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut options = Options::default();
|
||||||
|
let estimation = self
|
||||||
|
.contract
|
||||||
|
.estimate_gas(
|
||||||
|
ETH_BURN_FUNCTION_NAME,
|
||||||
|
(
|
||||||
|
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||||
|
Token::Uint(U256::from(&verification_key.to_bytes())),
|
||||||
|
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||||
|
Token::String(gateway_owner.clone()),
|
||||||
|
),
|
||||||
|
SecretKeyRef::from(&self.eth_private_key).address(),
|
||||||
|
options.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
options.gas = Some(estimation);
|
||||||
|
log::info!("Generating bandwidth on ETH contract in 10 seconds with an estimated gas of {}. \
|
||||||
|
Kill the process if you want to abort. Keep in mind that if you abort now, you'll still have \
|
||||||
|
some tokens approved for bandwidth spending from the previous action. \
|
||||||
|
If you don't want that, you'll need to manually decreaseAllowance to revert the approval.", estimation);
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
|
||||||
|
log::error!(
|
||||||
|
"the timer has gone away while waiting for possible kill! - {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let recipt = self
|
||||||
|
.contract
|
||||||
|
.signed_call_with_confirmations(
|
||||||
|
ETH_BURN_FUNCTION_NAME,
|
||||||
|
(
|
||||||
|
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||||
|
Token::Uint(U256::from(&verification_key.to_bytes())),
|
||||||
|
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||||
|
Token::String(gateway_owner),
|
||||||
|
),
|
||||||
|
options,
|
||||||
|
confirmations,
|
||||||
|
&self.eth_private_key,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
if Some(U64::from(0u64)) == recipt.status {
|
||||||
|
Err(GatewayClientError::BurnTokenError(
|
||||||
|
web3::Error::InvalidResponse(format!(
|
||||||
|
"Transaction status is 0 (failure): {:?}",
|
||||||
|
recipt.logs,
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
log::info!(
|
||||||
|
"Bought bandwidth on Ethereum: {} MB",
|
||||||
|
BANDWIDTH_VALUE / 1024 / 1024
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use network_defaults::ETH_EVENT_NAME;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_contract() {
|
||||||
|
let transport =
|
||||||
|
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
|
||||||
|
let web3 = web3::Web3::new(transport);
|
||||||
|
// test no panic occurs
|
||||||
|
eth_contract(web3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_erc20_contract() {
|
||||||
|
let transport =
|
||||||
|
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
|
||||||
|
let web3 = web3::Web3::new(transport);
|
||||||
|
// test no panic occurs
|
||||||
|
eth_erc20_contract(web3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_event_name_constant_against_abi() {
|
||||||
|
let transport =
|
||||||
|
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
|
||||||
|
let web3 = web3::Web3::new(transport);
|
||||||
|
let contract = eth_contract(web3);
|
||||||
|
assert!(contract.abi().event(ETH_EVENT_NAME).is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ use crate::wasm_storage::PersistentStorage;
|
|||||||
use coconut_interface::Credential;
|
use coconut_interface::Credential;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use credential_storage::PersistentStorage;
|
use credential_storage::PersistentStorage;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use credentials::token::bandwidth::TokenCredential;
|
||||||
use crypto::asymmetric::identity;
|
use crypto::asymmetric::identity;
|
||||||
use futures::{FutureExt, SinkExt, StreamExt};
|
use futures::{FutureExt, SinkExt, StreamExt};
|
||||||
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
|
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
|
||||||
@@ -28,8 +30,6 @@ use rand::rngs::OsRng;
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
use task::ShutdownListener;
|
|
||||||
use tungstenite::protocol::Message;
|
use tungstenite::protocol::Message;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@@ -65,10 +65,6 @@ pub struct GatewayClient {
|
|||||||
reconnection_attempts: usize,
|
reconnection_attempts: usize,
|
||||||
/// Delay between each subsequent reconnection attempt.
|
/// Delay between each subsequent reconnection attempt.
|
||||||
reconnection_backoff: Duration,
|
reconnection_backoff: Duration,
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
/// Listen to shutdown messages.
|
|
||||||
shutdown: Option<ShutdownListener>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GatewayClient {
|
impl GatewayClient {
|
||||||
@@ -84,7 +80,6 @@ impl GatewayClient {
|
|||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
response_timeout_duration: Duration,
|
response_timeout_duration: Duration,
|
||||||
bandwidth_controller: Option<BandwidthController<PersistentStorage>>,
|
bandwidth_controller: Option<BandwidthController<PersistentStorage>>,
|
||||||
#[cfg(not(target_arch = "wasm32"))] shutdown: Option<ShutdownListener>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
GatewayClient {
|
GatewayClient {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
@@ -96,19 +91,12 @@ impl GatewayClient {
|
|||||||
local_identity,
|
local_identity,
|
||||||
shared_key,
|
shared_key,
|
||||||
connection: SocketState::NotConnected,
|
connection: SocketState::NotConnected,
|
||||||
packet_router: PacketRouter::new(
|
packet_router: PacketRouter::new(ack_sender, mixnet_message_sender),
|
||||||
ack_sender,
|
|
||||||
mixnet_message_sender,
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
shutdown.clone(),
|
|
||||||
),
|
|
||||||
response_timeout_duration,
|
response_timeout_duration,
|
||||||
bandwidth_controller,
|
bandwidth_controller,
|
||||||
should_reconnect_on_failure: true,
|
should_reconnect_on_failure: true,
|
||||||
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
|
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
|
||||||
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
|
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +123,6 @@ impl GatewayClient {
|
|||||||
gateway_owner: String,
|
gateway_owner: String,
|
||||||
local_identity: Arc<identity::KeyPair>,
|
local_identity: Arc<identity::KeyPair>,
|
||||||
response_timeout_duration: Duration,
|
response_timeout_duration: Duration,
|
||||||
#[cfg(not(target_arch = "wasm32"))] shutdown: Option<ShutdownListener>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
|
|
||||||
@@ -143,12 +130,7 @@ impl GatewayClient {
|
|||||||
// perfectly fine here, because it's not meant to be used
|
// perfectly fine here, because it's not meant to be used
|
||||||
let (ack_tx, _) = mpsc::unbounded();
|
let (ack_tx, _) = mpsc::unbounded();
|
||||||
let (mix_tx, _) = mpsc::unbounded();
|
let (mix_tx, _) = mpsc::unbounded();
|
||||||
let packet_router = PacketRouter::new(
|
let packet_router = PacketRouter::new(ack_tx, mix_tx);
|
||||||
ack_tx,
|
|
||||||
mix_tx,
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
shutdown.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
GatewayClient {
|
GatewayClient {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
@@ -166,8 +148,6 @@ impl GatewayClient {
|
|||||||
should_reconnect_on_failure: false,
|
should_reconnect_on_failure: false,
|
||||||
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
|
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
|
||||||
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
|
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,33 +279,8 @@ impl GatewayClient {
|
|||||||
let mut fused_timeout = timeout.fuse();
|
let mut fused_timeout = timeout.fuse();
|
||||||
let mut fused_stream = conn.fuse();
|
let mut fused_stream = conn.fuse();
|
||||||
|
|
||||||
// Bit of an ugly workaround for selecting on an `Option` without having access to
|
|
||||||
// `tokio::select`
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
let shutdown = {
|
|
||||||
let m_shutdown = self.shutdown.clone();
|
|
||||||
async {
|
|
||||||
if let Some(mut s) = m_shutdown {
|
|
||||||
s.recv().await
|
|
||||||
} else {
|
|
||||||
std::future::pending::<()>().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fuse()
|
|
||||||
};
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
tokio::pin!(shutdown);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
let mut shutdown = std::future::pending::<()>().fuse();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
futures::select! {
|
futures::select! {
|
||||||
_ = shutdown => {
|
|
||||||
log::trace!("GatewayClient control response: Received shutdown");
|
|
||||||
log::debug!("GatewayClient control response: Exiting");
|
|
||||||
break Err(GatewayClientError::ConnectionClosedGatewayShutdown);
|
|
||||||
}
|
|
||||||
_ = &mut fused_timeout => {
|
_ = &mut fused_timeout => {
|
||||||
break Err(GatewayClientError::Timeout);
|
break Err(GatewayClientError::Timeout);
|
||||||
}
|
}
|
||||||
@@ -336,16 +291,14 @@ impl GatewayClient {
|
|||||||
};
|
};
|
||||||
match ws_msg {
|
match ws_msg {
|
||||||
Message::Binary(bin_msg) => {
|
Message::Binary(bin_msg) => {
|
||||||
if let Err(err) = self.packet_router.route_received(vec![bin_msg]) {
|
self.packet_router.route_received(vec![bin_msg]);
|
||||||
log::warn!("Route received failed: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Message::Text(txt_msg) => {
|
Message::Text(txt_msg) => {
|
||||||
break ServerResponse::try_from(txt_msg).map_err(|_| GatewayClientError::MalformedResponse);
|
break ServerResponse::try_from(txt_msg).map_err(|_| GatewayClientError::MalformedResponse);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,6 +505,30 @@ impl GatewayClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
async fn claim_token_bandwidth(
|
||||||
|
&mut self,
|
||||||
|
credential: TokenCredential,
|
||||||
|
) -> Result<(), GatewayClientError> {
|
||||||
|
let mut rng = OsRng;
|
||||||
|
|
||||||
|
let iv = IV::new_random(&mut rng);
|
||||||
|
|
||||||
|
let msg = ClientControlRequest::new_enc_token_bandwidth_credential(
|
||||||
|
&credential,
|
||||||
|
self.shared_key.as_ref().unwrap(),
|
||||||
|
iv,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
|
||||||
|
ServerResponse::Bandwidth { available_total } => Ok(available_total),
|
||||||
|
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
|
||||||
|
_ => Err(GatewayClientError::UnexpectedResponse),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn try_claim_testnet_bandwidth(&mut self) -> Result<(), GatewayClientError> {
|
async fn try_claim_testnet_bandwidth(&mut self) -> Result<(), GatewayClientError> {
|
||||||
let msg = ClientControlRequest::ClaimFreeTestnetBandwidth.into();
|
let msg = ClientControlRequest::ClaimFreeTestnetBandwidth.into();
|
||||||
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
|
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
|
||||||
@@ -590,10 +567,17 @@ impl GatewayClient {
|
|||||||
.prepare_coconut_credential()
|
.prepare_coconut_credential()
|
||||||
.await?;
|
.await?;
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
return self.try_claim_testnet_bandwidth().await;
|
let credential = self
|
||||||
|
.bandwidth_controller
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.prepare_token_credential(self.gateway_identity, _gateway_owner)
|
||||||
|
.await?;
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(feature = "coconut")]
|
||||||
return self.claim_coconut_bandwidth(credential).await;
|
return self.claim_coconut_bandwidth(credential).await;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
return self.claim_token_bandwidth(credential).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
||||||
@@ -739,8 +723,6 @@ impl GatewayClient {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("no shared key present even though we're authenticated!"),
|
.expect("no shared key present even though we're authenticated!"),
|
||||||
),
|
),
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
self.shutdown.clone(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|||||||
@@ -64,9 +64,6 @@ pub enum GatewayClientError {
|
|||||||
#[error("Connection was abruptly closed")]
|
#[error("Connection was abruptly closed")]
|
||||||
ConnectionAbruptlyClosed,
|
ConnectionAbruptlyClosed,
|
||||||
|
|
||||||
#[error("Connection was abruptly closed as gateway was stopped")]
|
|
||||||
ConnectionClosedGatewayShutdown,
|
|
||||||
|
|
||||||
#[error("Received response was malformed")]
|
#[error("Received response was malformed")]
|
||||||
MalformedResponse,
|
MalformedResponse,
|
||||||
|
|
||||||
@@ -96,9 +93,6 @@ pub enum GatewayClientError {
|
|||||||
|
|
||||||
#[error("Timed out")]
|
#[error("Timed out")]
|
||||||
Timeout,
|
Timeout,
|
||||||
|
|
||||||
#[error("Failed to send mixnet message")]
|
|
||||||
MixnetMsgSenderFailedToSend,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GatewayClientError {
|
impl GatewayClientError {
|
||||||
|
|||||||
@@ -8,10 +8,6 @@ use futures::channel::mpsc;
|
|||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::nodes::MAX_NODE_ADDRESS_UNPADDED_LEN;
|
use nymsphinx::addressing::nodes::MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||||
use nymsphinx::params::packet_sizes::PacketSize;
|
use nymsphinx::params::packet_sizes::PacketSize;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
use task::ShutdownListener;
|
|
||||||
|
|
||||||
use crate::error::GatewayClientError;
|
|
||||||
|
|
||||||
pub type MixnetMessageSender = mpsc::UnboundedSender<Vec<Vec<u8>>>;
|
pub type MixnetMessageSender = mpsc::UnboundedSender<Vec<Vec<u8>>>;
|
||||||
pub type MixnetMessageReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
|
pub type MixnetMessageReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
|
||||||
@@ -23,28 +19,20 @@ pub type AcknowledgementReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
|
|||||||
pub struct PacketRouter {
|
pub struct PacketRouter {
|
||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
mixnet_message_sender: MixnetMessageSender,
|
mixnet_message_sender: MixnetMessageSender,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
shutdown: Option<ShutdownListener>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketRouter {
|
impl PacketRouter {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
mixnet_message_sender: MixnetMessageSender,
|
mixnet_message_sender: MixnetMessageSender,
|
||||||
#[cfg(not(target_arch = "wasm32"))] shutdown: Option<ShutdownListener>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
PacketRouter {
|
PacketRouter {
|
||||||
ack_sender,
|
ack_sender,
|
||||||
mixnet_message_sender,
|
mixnet_message_sender,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
shutdown,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn route_received(
|
pub fn route_received(&self, unwrapped_packets: Vec<Vec<u8>>) {
|
||||||
&mut self,
|
|
||||||
unwrapped_packets: Vec<Vec<u8>>,
|
|
||||||
) -> Result<(), GatewayClientError> {
|
|
||||||
let mut received_messages = Vec::new();
|
let mut received_messages = Vec::new();
|
||||||
let mut received_acks = Vec::new();
|
let mut received_acks = Vec::new();
|
||||||
|
|
||||||
@@ -72,29 +60,24 @@ impl PacketRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// due to how we are currently using it, those unwraps can't fail, but if we ever
|
||||||
|
// wanted to make `gateway-client` into some more generic library, we would probably need
|
||||||
|
// to catch that error or something.
|
||||||
if !received_messages.is_empty() {
|
if !received_messages.is_empty() {
|
||||||
trace!("routing 'real'");
|
trace!("routing 'real'");
|
||||||
if let Err(err) = self.mixnet_message_sender.unbounded_send(received_messages) {
|
self.mixnet_message_sender
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
.unbounded_send(received_messages)
|
||||||
if let Some(shutdown) = &mut self.shutdown {
|
.unwrap();
|
||||||
if shutdown.is_shutdown_poll() {
|
|
||||||
// This should ideally not happen, but it's ok
|
|
||||||
log::warn!("Failed to send mixnet message due to receiver task shutdown");
|
|
||||||
return Err(GatewayClientError::MixnetMsgSenderFailedToSend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This should never happen during ordinary operation the way it's currently used.
|
|
||||||
// Abort to be on the safe side
|
|
||||||
panic!("Failed to send mixnet message: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !received_acks.is_empty() {
|
if !received_acks.is_empty() {
|
||||||
trace!("routing acks");
|
trace!("routing acks");
|
||||||
if let Err(e) = self.ack_sender.unbounded_send(received_acks) {
|
match self.ack_sender.unbounded_send(received_acks) {
|
||||||
error!("failed to send ack: {:?}", e);
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to send ack: {:?}", e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ use gateway_requests::registration::handshake::SharedKeys;
|
|||||||
use gateway_requests::BinaryResponse;
|
use gateway_requests::BinaryResponse;
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
use task::ShutdownListener;
|
|
||||||
use tungstenite::Message;
|
use tungstenite::Message;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@@ -46,9 +44,9 @@ pub(crate) struct PartiallyDelegated {
|
|||||||
impl PartiallyDelegated {
|
impl PartiallyDelegated {
|
||||||
fn route_socket_message(
|
fn route_socket_message(
|
||||||
ws_msg: Message,
|
ws_msg: Message,
|
||||||
packet_router: &mut PacketRouter,
|
packet_router: &PacketRouter,
|
||||||
shared_key: &SharedKeys,
|
shared_key: &SharedKeys,
|
||||||
) -> Result<(), GatewayClientError> {
|
) {
|
||||||
match ws_msg {
|
match ws_msg {
|
||||||
Message::Binary(bin_msg) => {
|
Message::Binary(bin_msg) => {
|
||||||
// this function decrypts the request and checks the MAC
|
// this function decrypts the request and checks the MAC
|
||||||
@@ -62,7 +60,7 @@ impl PartiallyDelegated {
|
|||||||
"message received from the gateway was malformed! - {:?}",
|
"message received from the gateway was malformed! - {:?}",
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,22 +74,18 @@ impl PartiallyDelegated {
|
|||||||
// This would also require NOT discarding any text responses here.
|
// This would also require NOT discarding any text responses here.
|
||||||
|
|
||||||
// TODO: those can return the "send confirmations" - perhaps it should be somehow worked around?
|
// TODO: those can return the "send confirmations" - perhaps it should be somehow worked around?
|
||||||
Message::Text(text) => {
|
Message::Text(text) => trace!(
|
||||||
trace!(
|
"received a text message - probably a response to some previous query! - {}",
|
||||||
"received a text message - probably a response to some previous query! - {}",
|
text
|
||||||
text
|
),
|
||||||
);
|
_ => (),
|
||||||
Ok(())
|
};
|
||||||
}
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn split_and_listen_for_mixnet_messages(
|
pub(crate) fn split_and_listen_for_mixnet_messages(
|
||||||
conn: WsConn,
|
conn: WsConn,
|
||||||
packet_router: PacketRouter,
|
packet_router: PacketRouter,
|
||||||
shared_key: Arc<SharedKeys>,
|
shared_key: Arc<SharedKeys>,
|
||||||
#[cfg(not(target_arch = "wasm32"))] shutdown: Option<ShutdownListener>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// when called for, it NEEDS TO yield back the stream so that we could merge it and
|
// when called for, it NEEDS TO yield back the stream so that we could merge it and
|
||||||
// read control request responses.
|
// read control request responses.
|
||||||
@@ -103,36 +97,10 @@ impl PartiallyDelegated {
|
|||||||
let mixnet_receiver_future = async move {
|
let mixnet_receiver_future = async move {
|
||||||
let mut fused_receiver = notify_receiver.fuse();
|
let mut fused_receiver = notify_receiver.fuse();
|
||||||
let mut fused_stream = (&mut stream).fuse();
|
let mut fused_stream = (&mut stream).fuse();
|
||||||
let mut packet_router = packet_router;
|
|
||||||
|
|
||||||
// Bit of an ugly workaround for selecting on an `Option` without having access to
|
|
||||||
// `tokio::select`
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
let shutdown = {
|
|
||||||
let m_shutdown = shutdown.clone();
|
|
||||||
async {
|
|
||||||
if let Some(mut s) = m_shutdown {
|
|
||||||
s.recv().await
|
|
||||||
} else {
|
|
||||||
std::future::pending::<()>().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fuse()
|
|
||||||
};
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
tokio::pin!(shutdown);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
let mut shutdown = std::future::pending::<()>().fuse();
|
|
||||||
|
|
||||||
let ret_err = loop {
|
let ret_err = loop {
|
||||||
futures::select! {
|
futures::select! {
|
||||||
_ = shutdown => {
|
_ = fused_receiver => {
|
||||||
log::trace!("GatewayClient listener: Received shutdown");
|
|
||||||
log::debug!("GatewayClient listener: Exiting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ = &mut fused_receiver => {
|
|
||||||
break Ok(());
|
break Ok(());
|
||||||
}
|
}
|
||||||
msg = fused_stream.next() => {
|
msg = fused_stream.next() => {
|
||||||
@@ -140,9 +108,7 @@ impl PartiallyDelegated {
|
|||||||
Err(err) => break Err(err),
|
Err(err) => break Err(err),
|
||||||
Ok(msg) => msg
|
Ok(msg) => msg
|
||||||
};
|
};
|
||||||
if let Err(err) = Self::route_socket_message(ws_msg, &mut packet_router, shared_key.as_ref()) {
|
Self::route_socket_message(ws_msg, &packet_router, shared_key.as_ref());
|
||||||
log::warn!("Route socket message failed: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -196,10 +162,12 @@ impl PartiallyDelegated {
|
|||||||
.expect("stream sender was somehow dropped without sending anything!");
|
.expect("stream sender was somehow dropped without sending anything!");
|
||||||
|
|
||||||
if let Some(res) = receive_res {
|
if let Some(res) = receive_res {
|
||||||
let _res = res?;
|
if let Err(err) = res {
|
||||||
panic!(
|
// the receiver got an error. most likely a network one.
|
||||||
"This should have NEVER happened - returned a stream before receiving notification"
|
return Err(err);
|
||||||
)
|
} else {
|
||||||
|
panic!("This should have NEVER happened - returned a stream before receiving notification")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this call failing is incredibly unlikely, but not impossible.
|
// this call failing is incredibly unlikely, but not impossible.
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ pub struct CoconutCredential {
|
|||||||
pub signature: String,
|
pub signature: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ERC20Credential {
|
||||||
|
pub id: i64,
|
||||||
|
pub public_key: String,
|
||||||
|
pub private_key: String,
|
||||||
|
pub consumed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Storage: Send + Sync {
|
pub trait Storage: Send + Sync {
|
||||||
async fn insert_coconut_credential(
|
async fn insert_coconut_credential(
|
||||||
@@ -40,6 +47,16 @@ pub trait Storage: Send + Sync {
|
|||||||
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError>;
|
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError>;
|
||||||
|
|
||||||
async fn remove_coconut_credential(&self, id: i64) -> Result<(), StorageError>;
|
async fn remove_coconut_credential(&self, id: i64) -> Result<(), StorageError>;
|
||||||
|
|
||||||
|
async fn insert_erc20_credential(
|
||||||
|
&self,
|
||||||
|
public_key: String,
|
||||||
|
private_key: String,
|
||||||
|
) -> Result<(), StorageError>;
|
||||||
|
|
||||||
|
async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, StorageError>;
|
||||||
|
|
||||||
|
async fn consume_erc20_credential(&self, public_key: String) -> Result<(), StorageError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -62,4 +79,20 @@ impl Storage for PersistentStorage {
|
|||||||
async fn remove_coconut_credential(&self, _id: i64) -> Result<(), StorageError> {
|
async fn remove_coconut_credential(&self, _id: i64) -> Result<(), StorageError> {
|
||||||
Err(StorageError::WasmNotSupported)
|
Err(StorageError::WasmNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn insert_erc20_credential(
|
||||||
|
&self,
|
||||||
|
_public_key: String,
|
||||||
|
_private_key: String,
|
||||||
|
) -> Result<(), StorageError> {
|
||||||
|
Err(StorageError::WasmNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_next_erc20_credential(&self) -> Result<ERC20Credential, StorageError> {
|
||||||
|
Err(StorageError::WasmNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn consume_erc20_credential(&self, _public_key: String) -> Result<(), StorageError> {
|
||||||
|
Err(StorageError::WasmNotSupported)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ impl Client {
|
|||||||
address.into(),
|
address.into(),
|
||||||
receiver,
|
receiver,
|
||||||
initial_connection_timeout,
|
initial_connection_timeout,
|
||||||
¤t_reconnection_attempt,
|
&*current_reconnection_attempt,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ validator-api-requests = { path = "../../../validator-api/validator-api-requests
|
|||||||
async-trait = { version = "0.1.51", optional = true }
|
async-trait = { version = "0.1.51", optional = true }
|
||||||
bip39 = { version = "1", features = ["rand"], optional = true }
|
bip39 = { version = "1", features = ["rand"], optional = true }
|
||||||
config = { path = "../../config", optional = true }
|
config = { path = "../../config", optional = true }
|
||||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
cosmrs = { version = "0.7.0", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
||||||
prost = { version = "0.10", default-features = false, optional = true }
|
prost = { version = "0.10", default-features = false, optional = true }
|
||||||
flate2 = { version = "1.0.20", optional = true }
|
flate2 = { version = "1.0.20", optional = true }
|
||||||
sha2 = { version = "0.9.5", optional = true }
|
sha2 = { version = "0.9.5", optional = true }
|
||||||
|
|||||||
@@ -2,33 +2,36 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{validator_api, ValidatorClientError};
|
use crate::{validator_api, ValidatorClientError};
|
||||||
use mixnet_contract_common::mixnode::MixNodeDetails;
|
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||||
use mixnet_contract_common::NodeId;
|
|
||||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_api_requests::coconut::{
|
use validator_api_requests::coconut::{
|
||||||
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse, VerificationKeyResponse,
|
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
||||||
|
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
||||||
VerifyCredentialBody, VerifyCredentialResponse,
|
VerifyCredentialBody, VerifyCredentialResponse,
|
||||||
};
|
};
|
||||||
use validator_api_requests::models::{
|
use validator_api_requests::models::{
|
||||||
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
|
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||||
RewardEstimationResponse, StakeSaturationResponse,
|
StakeSaturationResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use crate::nymd::traits::MixnetQueryClient;
|
use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use crate::nymd::{self, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient};
|
use crate::nymd::{
|
||||||
|
self, error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use mixnet_contract_common::{
|
use mixnet_contract_common::{
|
||||||
mixnode::MixNodeBond,
|
mixnode::DelegationEvent, ContractStateParams, Delegation, IdentityKey, Interval,
|
||||||
pending_events::{PendingEpochEvent, PendingIntervalEvent},
|
MixnetContractVersion, MixnodeRewardingStatusResponse, RewardedSetNodeStatus,
|
||||||
Delegation, RewardedSetNodeStatus, UnbondedMixnode,
|
RewardedSetUpdateDetails,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use network_defaults::NymNetworkDetails;
|
use network_defaults::{all::Network, NymNetworkDetails};
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use validator_api_requests::models::MixNodeBondAnnotated;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -111,6 +114,9 @@ impl Config {
|
|||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
pub struct Client<C> {
|
pub struct Client<C> {
|
||||||
|
// compatibility : (
|
||||||
|
pub network: Network,
|
||||||
|
|
||||||
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
||||||
// non-trivial amount of work and it's out of scope of the current branch
|
// non-trivial amount of work and it's out of scope of the current branch
|
||||||
mnemonic: Option<bip39::Mnemonic>,
|
mnemonic: Option<bip39::Mnemonic>,
|
||||||
@@ -129,6 +135,9 @@ pub struct Client<C> {
|
|||||||
impl Client<SigningNymdClient> {
|
impl Client<SigningNymdClient> {
|
||||||
pub fn new_signing(
|
pub fn new_signing(
|
||||||
config: Config,
|
config: Config,
|
||||||
|
// we need to provide network argument due to compatibility with other components (wallet...)
|
||||||
|
// that rely on its existence...
|
||||||
|
network: Network,
|
||||||
mnemonic: bip39::Mnemonic,
|
mnemonic: bip39::Mnemonic,
|
||||||
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
||||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||||
@@ -140,6 +149,7 @@ impl Client<SigningNymdClient> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
|
network,
|
||||||
mnemonic: Some(mnemonic),
|
mnemonic: Some(mnemonic),
|
||||||
mixnode_page_limit: config.mixnode_page_limit,
|
mixnode_page_limit: config.mixnode_page_limit,
|
||||||
gateway_page_limit: config.gateway_page_limit,
|
gateway_page_limit: config.gateway_page_limit,
|
||||||
@@ -167,12 +177,18 @@ impl Client<SigningNymdClient> {
|
|||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
impl Client<QueryNymdClient> {
|
impl Client<QueryNymdClient> {
|
||||||
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
pub fn new_query(
|
||||||
|
config: Config,
|
||||||
|
// we need to provide network argument due to compatibility with other components (wallet...)
|
||||||
|
// that rely on its existence...
|
||||||
|
network: Network,
|
||||||
|
) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
||||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||||
let nymd_client =
|
let nymd_client =
|
||||||
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
|
network,
|
||||||
mnemonic: None,
|
mnemonic: None,
|
||||||
mixnode_page_limit: config.mixnode_page_limit,
|
mixnode_page_limit: config.mixnode_page_limit,
|
||||||
gateway_page_limit: config.gateway_page_limit,
|
gateway_page_limit: config.gateway_page_limit,
|
||||||
@@ -189,9 +205,12 @@ impl Client<QueryNymdClient> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nymd wrappers
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
impl<C> Client<C> {
|
impl<C> Client<C> {
|
||||||
|
pub fn change_validator_api(&mut self, new_endpoint: Url) {
|
||||||
|
self.validator_api.change_url(new_endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
// use case: somebody initialised client without a contract in order to upload and initialise one
|
// 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
|
// and now they want to actually use it without making new client
|
||||||
pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) {
|
pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) {
|
||||||
@@ -203,22 +222,203 @@ impl<C> Client<C> {
|
|||||||
self.nymd.mixnet_contract_address().clone()
|
self.nymd.mixnet_contract_address().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// basically handles paging for us
|
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
pub async fn get_all_nymd_rewarded_set_mixnodes(
|
Ok(self.validator_api.get_mixnodes().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_cached_mixnodes_detailed(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<(NodeId, RewardedSetNodeStatus)>, ValidatorClientError>
|
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_mixnodes_detailed().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_cached_rewarded_mixnodes(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_cached_rewarded_mixnodes_detailed(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_rewarded_mixnodes_detailed().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_cached_active_mixnodes(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_active_mixnodes().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_cached_active_mixnodes_detailed(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_active_mixnodes_detailed().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_gateways().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_contract_settings(&self) -> Result<ContractStateParams, ValidatorClientError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_contract_settings().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_operator_rewards(&self, address: String) -> Result<u128, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_operator_rewards(address).await?.u128())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_delegator_rewards(
|
||||||
|
&self,
|
||||||
|
address: String,
|
||||||
|
mix_identity: IdentityKey,
|
||||||
|
proxy: Option<String>,
|
||||||
|
) -> Result<u128, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self
|
||||||
|
.nymd
|
||||||
|
.get_delegator_rewards(address, mix_identity, proxy)
|
||||||
|
.await?
|
||||||
|
.u128())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_pending_delegation_events(
|
||||||
|
&self,
|
||||||
|
owner_address: String,
|
||||||
|
proxy_address: Option<String>,
|
||||||
|
) -> Result<Vec<DelegationEvent>, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self
|
||||||
|
.nymd
|
||||||
|
.get_pending_delegation_events(owner_address, proxy_address)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_current_epoch(&self) -> Result<Interval, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_current_epoch().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_current_operator_cost(&self) -> Result<u64, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_current_operator_cost().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
self.nymd.get_mixnet_contract_version().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_rewarding_status(
|
||||||
|
&self,
|
||||||
|
mix_identity: mixnet_contract_common::IdentityKey,
|
||||||
|
rewarding_interval_nonce: u32,
|
||||||
|
) -> Result<MixnodeRewardingStatusResponse, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self
|
||||||
|
.nymd
|
||||||
|
.get_rewarding_status(mix_identity, rewarding_interval_nonce)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_reward_pool(&self) -> Result<u128, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_reward_pool().await?.u128())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_circulating_supply().await?.u128())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_sybil_resistance_percent(&self) -> Result<u8, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_sybil_resistance_percent().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_active_set_work_factor(&self) -> Result<u8, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_active_set_work_factor().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_epochs_in_interval(&self) -> Result<u64, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_epochs_in_interval().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_interval_reward_percent(&self) -> Result<u8, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self.nymd.get_interval_reward_percent().await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_current_rewarded_set_update_details(
|
||||||
|
&self,
|
||||||
|
) -> Result<RewardedSetUpdateDetails, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
Ok(self
|
||||||
|
.nymd
|
||||||
|
.query_current_rewarded_set_update_details()
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
// basically handles paging for us
|
||||||
|
pub async fn get_all_nymd_rewarded_set_mixnode_identities(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<(IdentityKey, RewardedSetNodeStatus)>, ValidatorClientError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut identities = Vec::new();
|
let mut identities = Vec::new();
|
||||||
let mut start_after = None;
|
let mut start_after = None;
|
||||||
|
let mut height = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut paged_response = self
|
let mut paged_response = self
|
||||||
.nymd
|
.nymd
|
||||||
.get_rewarded_set_paged(start_after.take(), self.rewarded_set_page_limit)
|
.get_rewarded_set_identities_paged(
|
||||||
|
start_after.take(),
|
||||||
|
self.rewarded_set_page_limit,
|
||||||
|
height,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
identities.append(&mut paged_response.nodes);
|
identities.append(&mut paged_response.identities);
|
||||||
|
|
||||||
|
if height.is_none() {
|
||||||
|
// keep using the same height (the first query happened at the most recent height)
|
||||||
|
height = Some(paged_response.at_height)
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(start_after_res) = paged_response.start_next_after {
|
if let Some(start_after_res) = paged_response.start_next_after {
|
||||||
start_after = Some(start_after_res)
|
start_after = Some(start_after_res)
|
||||||
@@ -230,122 +430,83 @@ impl<C> Client<C> {
|
|||||||
Ok(identities)
|
Ok(identities)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_nymd_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
pub async fn get_nymd_rewarded_and_active_sets(
|
||||||
|
&self,
|
||||||
|
) -> Result<Vec<(MixNodeBond, RewardedSetNodeStatus)>, ValidatorClientError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut mixnodes = Vec::new();
|
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
|
||||||
let mut start_after = None;
|
let rewarded_set_identities = self
|
||||||
loop {
|
.get_all_nymd_rewarded_set_mixnode_identities()
|
||||||
let mut paged_response = self
|
.await?
|
||||||
.nymd
|
.into_iter()
|
||||||
.get_mixnode_bonds_paged(self.mixnode_page_limit, start_after.take())
|
.collect::<HashMap<_, _>>();
|
||||||
.await?;
|
|
||||||
mixnodes.append(&mut paged_response.nodes);
|
|
||||||
|
|
||||||
if let Some(start_after_res) = paged_response.start_next_after {
|
Ok(all_mixnodes
|
||||||
start_after = Some(start_after_res)
|
.into_iter()
|
||||||
} else {
|
.filter_map(|node| {
|
||||||
break;
|
rewarded_set_identities
|
||||||
}
|
.get(node.identity())
|
||||||
}
|
.map(|status| (node, *status))
|
||||||
|
})
|
||||||
Ok(mixnodes)
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_nymd_mixnodes_detailed(
|
/// If you need both rewarded and the active set, consider using [Self::get_nymd_rewarded_and_active_sets] instead
|
||||||
&self,
|
pub async fn get_nymd_rewarded_set(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError>
|
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut mixnodes = Vec::new();
|
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
|
||||||
let mut start_after = None;
|
let rewarded_set_identities = self
|
||||||
loop {
|
.get_all_nymd_rewarded_set_mixnode_identities()
|
||||||
let mut paged_response = self
|
.await?
|
||||||
.nymd
|
.into_iter()
|
||||||
.get_mixnodes_detailed_paged(self.mixnode_page_limit, start_after.take())
|
.map(|(identity, _status)| identity)
|
||||||
.await?;
|
.collect::<HashSet<_>>();
|
||||||
mixnodes.append(&mut paged_response.nodes);
|
|
||||||
|
|
||||||
if let Some(start_after_res) = paged_response.start_next_after {
|
Ok(all_mixnodes
|
||||||
start_after = Some(start_after_res)
|
.into_iter()
|
||||||
} else {
|
.filter(|node| rewarded_set_identities.contains(node.identity()))
|
||||||
break;
|
.collect())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mixnodes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_nymd_unbonded_mixnodes(
|
/// If you need both rewarded and the active set, consider using [Self::get_nymd_rewarded_and_active_sets] instead
|
||||||
&self,
|
pub async fn get_nymd_active_set(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||||
) -> Result<Vec<(NodeId, UnbondedMixnode)>, ValidatorClientError>
|
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut mixnodes = Vec::new();
|
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
|
||||||
let mut start_after = None;
|
let active_set_identities = self
|
||||||
loop {
|
.get_all_nymd_rewarded_set_mixnode_identities()
|
||||||
let mut paged_response = self
|
.await?
|
||||||
.nymd
|
.into_iter()
|
||||||
.get_unbonded_paged(self.mixnode_page_limit, start_after.take())
|
.filter_map(|(identity, status)| {
|
||||||
.await?;
|
if status.is_active() {
|
||||||
mixnodes.append(&mut paged_response.nodes);
|
Some(identity)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
if let Some(start_after_res) = paged_response.start_next_after {
|
Ok(all_mixnodes
|
||||||
start_after = Some(start_after_res)
|
.into_iter()
|
||||||
} else {
|
.filter(|node| active_set_identities.contains(node.identity()))
|
||||||
break;
|
.collect())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mixnodes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_nymd_unbonded_mixnodes_by_owner(
|
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||||
&self,
|
|
||||||
owner: &cosmrs::AccountId,
|
|
||||||
) -> Result<Vec<(NodeId, UnbondedMixnode)>, ValidatorClientError>
|
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut mixnodes = Vec::new();
|
let mut mixnodes = Vec::new();
|
||||||
let mut start_after = None;
|
let mut start_after = None;
|
||||||
loop {
|
loop {
|
||||||
let mut paged_response = self
|
let mut paged_response = self
|
||||||
.nymd
|
.nymd
|
||||||
.get_unbonded_by_owner_paged(owner, self.mixnode_page_limit, start_after.take())
|
.get_mixnodes_paged(start_after.take(), self.mixnode_page_limit)
|
||||||
.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_nymd_unbonded_mixnodes_by_identity(
|
|
||||||
&self,
|
|
||||||
identity_key: String,
|
|
||||||
) -> Result<Vec<(NodeId, UnbondedMixnode)>, ValidatorClientError>
|
|
||||||
where
|
|
||||||
C: CosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
let mut mixnodes = Vec::new();
|
|
||||||
let mut start_after = None;
|
|
||||||
loop {
|
|
||||||
let mut paged_response = self
|
|
||||||
.nymd
|
|
||||||
.get_unbonded_by_identity_paged(
|
|
||||||
identity_key.clone(),
|
|
||||||
self.mixnode_page_limit,
|
|
||||||
start_after.take(),
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
mixnodes.append(&mut paged_response.nodes);
|
mixnodes.append(&mut paged_response.nodes);
|
||||||
|
|
||||||
@@ -361,7 +522,7 @@ impl<C> Client<C> {
|
|||||||
|
|
||||||
pub async fn get_all_nymd_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
|
pub async fn get_all_nymd_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut gateways = Vec::new();
|
let mut gateways = Vec::new();
|
||||||
let mut start_after = None;
|
let mut start_after = None;
|
||||||
@@ -384,18 +545,18 @@ impl<C> Client<C> {
|
|||||||
|
|
||||||
pub async fn get_all_nymd_single_mixnode_delegations(
|
pub async fn get_all_nymd_single_mixnode_delegations(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
identity: IdentityKey,
|
||||||
) -> Result<Vec<Delegation>, ValidatorClientError>
|
) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut delegations = Vec::new();
|
let mut delegations = Vec::new();
|
||||||
let mut start_after = None;
|
let mut start_after = None;
|
||||||
loop {
|
loop {
|
||||||
let mut paged_response = self
|
let mut paged_response = self
|
||||||
.nymd
|
.nymd
|
||||||
.get_mixnode_delegations_paged(
|
.get_mix_delegations_paged(
|
||||||
mix_id,
|
identity.clone(),
|
||||||
start_after.take(),
|
start_after.take(),
|
||||||
self.mixnode_delegations_page_limit,
|
self.mixnode_delegations_page_limit,
|
||||||
)
|
)
|
||||||
@@ -417,7 +578,7 @@ impl<C> Client<C> {
|
|||||||
delegation_owner: &cosmrs::AccountId,
|
delegation_owner: &cosmrs::AccountId,
|
||||||
) -> Result<Vec<Delegation>, ValidatorClientError>
|
) -> Result<Vec<Delegation>, ValidatorClientError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync + Send,
|
C: CosmWasmClient + Sync,
|
||||||
{
|
{
|
||||||
let mut delegations = Vec::new();
|
let mut delegations = Vec::new();
|
||||||
let mut start_after = None;
|
let mut start_after = None;
|
||||||
@@ -442,128 +603,10 @@ impl<C> Client<C> {
|
|||||||
Ok(delegations)
|
Ok(delegations)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_network_delegations(&self) -> Result<Vec<Delegation>, ValidatorClientError>
|
pub async fn get_mixnode_avg_uptimes(
|
||||||
where
|
|
||||||
C: CosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
let mut delegations = Vec::new();
|
|
||||||
let mut start_after = None;
|
|
||||||
loop {
|
|
||||||
let mut paged_response = self
|
|
||||||
.nymd
|
|
||||||
.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_nymd_pending_epoch_events(
|
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<PendingEpochEvent>, ValidatorClientError>
|
) -> Result<Vec<UptimeResponse>, ValidatorClientError> {
|
||||||
where
|
Ok(self.validator_api.get_mixnode_avg_uptimes().await?)
|
||||||
C: CosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
let mut events = Vec::new();
|
|
||||||
let mut start_after = None;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut paged_response = self
|
|
||||||
.nymd
|
|
||||||
.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_nymd_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
|
|
||||||
.nymd
|
|
||||||
.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
|
|
||||||
#[cfg(feature = "nymd-client")]
|
|
||||||
impl<C> Client<C> {
|
|
||||||
pub fn change_validator_api(&mut self, new_endpoint: Url) {
|
|
||||||
self.validator_api.change_url(new_endpoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_mixnodes().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_mixnodes_detailed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_mixnodes_detailed().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_rewarded_mixnodes(
|
|
||||||
&self,
|
|
||||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_rewarded_mixnodes_detailed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_rewarded_mixnodes_detailed().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_active_mixnodes(
|
|
||||||
&self,
|
|
||||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_active_mixnodes().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_active_mixnodes_detailed(
|
|
||||||
&self,
|
|
||||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_active_mixnodes_detailed().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_gateways().await?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn blind_sign(
|
pub async fn blind_sign(
|
||||||
@@ -601,17 +644,17 @@ impl ApiClient {
|
|||||||
|
|
||||||
pub async fn get_cached_active_mixnodes(
|
pub async fn get_cached_active_mixnodes(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
Ok(self.validator_api.get_active_mixnodes().await?)
|
Ok(self.validator_api.get_active_mixnodes().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_cached_rewarded_mixnodes(
|
pub async fn get_cached_rewarded_mixnodes(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
Ok(self.validator_api.get_mixnodes().await?)
|
Ok(self.validator_api.get_mixnodes().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +666,7 @@ impl ApiClient {
|
|||||||
&self,
|
&self,
|
||||||
identity: IdentityKeyRef<'_>,
|
identity: IdentityKeyRef<'_>,
|
||||||
since: Option<i64>,
|
since: Option<i64>,
|
||||||
) -> Result<GatewayCoreStatusResponse, ValidatorClientError> {
|
) -> Result<CoreNodeStatusResponse, ValidatorClientError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.validator_api
|
.validator_api
|
||||||
.get_gateway_core_status_count(identity, since)
|
.get_gateway_core_status_count(identity, since)
|
||||||
@@ -632,39 +675,39 @@ impl ApiClient {
|
|||||||
|
|
||||||
pub async fn get_mixnode_core_status_count(
|
pub async fn get_mixnode_core_status_count(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
identity: IdentityKeyRef<'_>,
|
||||||
since: Option<i64>,
|
since: Option<i64>,
|
||||||
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
|
) -> Result<CoreNodeStatusResponse, ValidatorClientError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.validator_api
|
.validator_api
|
||||||
.get_mixnode_core_status_count(mix_id, since)
|
.get_mixnode_core_status_count(identity, since)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_mixnode_status(
|
pub async fn get_mixnode_status(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
identity: IdentityKeyRef<'_>,
|
||||||
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
|
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
|
||||||
Ok(self.validator_api.get_mixnode_status(mix_id).await?)
|
Ok(self.validator_api.get_mixnode_status(identity).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_mixnode_reward_estimation(
|
pub async fn get_mixnode_reward_estimation(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
identity: IdentityKeyRef<'_>,
|
||||||
) -> Result<RewardEstimationResponse, ValidatorClientError> {
|
) -> Result<RewardEstimationResponse, ValidatorClientError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.validator_api
|
.validator_api
|
||||||
.get_mixnode_reward_estimation(mix_id)
|
.get_mixnode_reward_estimation(identity)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_mixnode_stake_saturation(
|
pub async fn get_mixnode_stake_saturation(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
identity: IdentityKeyRef<'_>,
|
||||||
) -> Result<StakeSaturationResponse, ValidatorClientError> {
|
) -> Result<StakeSaturationResponse, ValidatorClientError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.validator_api
|
.validator_api
|
||||||
.get_mixnode_stake_saturation(mix_id)
|
.get_mixnode_stake_saturation(identity)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,10 +734,6 @@ impl ApiClient {
|
|||||||
Ok(self.validator_api.get_coconut_verification_key().await?)
|
Ok(self.validator_api.get_coconut_verification_key().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_cosmos_address(&self) -> Result<CosmosAddressResponse, ValidatorClientError> {
|
|
||||||
Ok(self.validator_api.get_cosmos_address().await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn verify_bandwidth_credential(
|
pub async fn verify_bandwidth_credential(
|
||||||
&self,
|
&self,
|
||||||
request_body: &VerifyCredentialBody,
|
request_body: &VerifyCredentialBody,
|
||||||
@@ -704,4 +743,24 @@ impl ApiClient {
|
|||||||
.verify_bandwidth_credential(request_body)
|
.verify_bandwidth_credential(request_body)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn propose_release_funds(
|
||||||
|
&self,
|
||||||
|
request_body: &ProposeReleaseFundsRequestBody,
|
||||||
|
) -> Result<ProposeReleaseFundsResponse, ValidatorClientError> {
|
||||||
|
Ok(self
|
||||||
|
.validator_api
|
||||||
|
.propose_release_funds(request_body)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute_release_funds(
|
||||||
|
&self,
|
||||||
|
request_body: &ExecuteReleaseFundsRequestBody,
|
||||||
|
) -> Result<(), ValidatorClientError> {
|
||||||
|
Ok(self
|
||||||
|
.validator_api
|
||||||
|
.execute_release_funds(request_body)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
use crate::nymd::error::NymdError;
|
use crate::nymd::error::NymdError;
|
||||||
use crate::nymd::{Config as ClientConfig, NymdClient, QueryNymdClient};
|
use crate::nymd::{Config as ClientConfig, NymdClient, QueryNymdClient};
|
||||||
use crate::ApiClient;
|
use crate::ApiClient;
|
||||||
|
use network_defaults::all::Network;
|
||||||
|
|
||||||
use crate::nymd::traits::MixnetQueryClient;
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use network_defaults::NymNetworkDetails;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::BuildHasher;
|
use std::hash::BuildHasher;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -18,12 +17,12 @@ const CONNECTION_TEST_TIMEOUT_SEC: u64 = 2;
|
|||||||
|
|
||||||
// Run connection tests for all specified nymd and api urls. These are all run concurrently.
|
// Run connection tests for all specified nymd and api urls. These are all run concurrently.
|
||||||
pub async fn run_validator_connection_test<H: BuildHasher + 'static>(
|
pub async fn run_validator_connection_test<H: BuildHasher + 'static>(
|
||||||
nymd_urls: impl Iterator<Item = (NymNetworkDetails, Url)>,
|
nymd_urls: impl Iterator<Item = (Network, Url)>,
|
||||||
api_urls: impl Iterator<Item = (NymNetworkDetails, Url)>,
|
api_urls: impl Iterator<Item = (Network, Url)>,
|
||||||
mixnet_contract_address: HashMap<NymNetworkDetails, cosmrs::AccountId, H>,
|
mixnet_contract_address: HashMap<Network, cosmrs::AccountId, H>,
|
||||||
) -> (
|
) -> (
|
||||||
HashMap<NymNetworkDetails, Vec<(Url, bool)>>,
|
HashMap<Network, Vec<(Url, bool)>>,
|
||||||
HashMap<NymNetworkDetails, Vec<(Url, bool)>>,
|
HashMap<Network, Vec<(Url, bool)>>,
|
||||||
) {
|
) {
|
||||||
// Setup all the clients for the connection tests
|
// Setup all the clients for the connection tests
|
||||||
let connection_test_clients =
|
let connection_test_clients =
|
||||||
@@ -46,16 +45,16 @@ pub async fn run_validator_connection_test<H: BuildHasher + 'static>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_connection_tests<H: BuildHasher + 'static>(
|
fn setup_connection_tests<H: BuildHasher + 'static>(
|
||||||
nymd_urls: impl Iterator<Item = (NymNetworkDetails, Url)>,
|
nymd_urls: impl Iterator<Item = (Network, Url)>,
|
||||||
api_urls: impl Iterator<Item = (NymNetworkDetails, Url)>,
|
api_urls: impl Iterator<Item = (Network, Url)>,
|
||||||
mixnet_contract_address: HashMap<NymNetworkDetails, cosmrs::AccountId, H>,
|
mixnet_contract_address: HashMap<Network, cosmrs::AccountId, H>,
|
||||||
) -> impl Iterator<Item = ClientForConnectionTest> {
|
) -> impl Iterator<Item = ClientForConnectionTest> {
|
||||||
let nymd_connection_test_clients = nymd_urls.filter_map(move |(network, url)| {
|
let nymd_connection_test_clients = nymd_urls.filter_map(move |(network, url)| {
|
||||||
let address = mixnet_contract_address
|
let address = mixnet_contract_address
|
||||||
.get(&network)
|
.get(&network)
|
||||||
.expect("No configured contract address")
|
.expect("No configured contract address")
|
||||||
.clone();
|
.clone();
|
||||||
let config = ClientConfig::try_from_nym_network_details(&network)
|
let config = ClientConfig::try_from_nym_network_details(&network.details())
|
||||||
.expect("failed to create valid nymd client config");
|
.expect("failed to create valid nymd client config");
|
||||||
|
|
||||||
if let Ok(mut client) = NymdClient::<QueryNymdClient>::connect(config, url.as_str()) {
|
if let Ok(mut client) = NymdClient::<QueryNymdClient>::connect(config, url.as_str()) {
|
||||||
@@ -81,7 +80,7 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
|
|||||||
fn extract_and_collect_results_into_map(
|
fn extract_and_collect_results_into_map(
|
||||||
connection_results: &[ConnectionResult],
|
connection_results: &[ConnectionResult],
|
||||||
url_type: &UrlType,
|
url_type: &UrlType,
|
||||||
) -> HashMap<NymNetworkDetails, Vec<(Url, bool)>> {
|
) -> HashMap<Network, Vec<(Url, bool)>> {
|
||||||
connection_results
|
connection_results
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|c| &c.url_type() == url_type)
|
.filter(|c| &c.url_type() == url_type)
|
||||||
@@ -93,7 +92,7 @@ fn extract_and_collect_results_into_map(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn test_nymd_connection(
|
async fn test_nymd_connection(
|
||||||
network: NymNetworkDetails,
|
network: Network,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
client: &NymdClient<QueryNymdClient>,
|
client: &NymdClient<QueryNymdClient>,
|
||||||
) -> ConnectionResult {
|
) -> ConnectionResult {
|
||||||
@@ -105,47 +104,56 @@ async fn test_nymd_connection(
|
|||||||
{
|
{
|
||||||
Ok(Err(NymdError::TendermintError(e))) => {
|
Ok(Err(NymdError::TendermintError(e))) => {
|
||||||
// If we get a tendermint-rpc error, we classify the node as not contactable
|
// If we get a tendermint-rpc error, we classify the node as not contactable
|
||||||
log::debug!("Checking: nymd_url: {url}: {}: {}", "failed".red(), e);
|
log::debug!(
|
||||||
|
"Checking: nymd_url: {network}: {url}: {}: {}",
|
||||||
|
"failed".red(),
|
||||||
|
e
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Ok(Err(NymdError::AbciError(code, log))) => {
|
Ok(Err(NymdError::AbciError(code, log))) => {
|
||||||
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
|
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
|
||||||
// for example on a pre-launch network.
|
// for example on a pre-launch network.
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Checking: nymd_url: {url}: {}, but with abci error: {code}: {log}",
|
"Checking: nymd_url: {network}: {url}: {}, but with abci error: {code}: {log}",
|
||||||
"success".green()
|
"success".green()
|
||||||
);
|
);
|
||||||
code == 18
|
code == 18
|
||||||
}
|
}
|
||||||
Ok(Err(error @ NymdError::NoContractAddressAvailable)) => {
|
Ok(Err(error @ NymdError::NoContractAddressAvailable)) => {
|
||||||
log::debug!("Checking: nymd_url: {url}: {}: {error}", "failed".red());
|
log::debug!(
|
||||||
|
"Checking: nymd_url: {network}: {url}: {}: {error}",
|
||||||
|
"failed".red()
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
// For any other error, we're optimistic and just try anyway.
|
// For any other error, we're optimistic and just try anyway.
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Checking: nymd_url: {url}: {}, but with error: {e}",
|
"Checking: nymd_url: {network}: {url}: {}, but with error: {e}",
|
||||||
"success".green()
|
"success".green()
|
||||||
);
|
);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Ok(Ok(_)) => {
|
Ok(Ok(_)) => {
|
||||||
log::debug!("Checking: nymd_url: {url}: {}", "success".green());
|
log::debug!(
|
||||||
|
"Checking: nymd_url: {network}: {url}: {}",
|
||||||
|
"success".green()
|
||||||
|
);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!("Checking: nymd_url: {url}: {}: {e}", "failed".red());
|
log::debug!(
|
||||||
|
"Checking: nymd_url: {network}: {url}: {}: {e}",
|
||||||
|
"failed".red()
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ConnectionResult::Nymd(network, url.clone(), result)
|
ConnectionResult::Nymd(network, url.clone(), result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn test_api_connection(
|
async fn test_api_connection(network: Network, url: &Url, client: &ApiClient) -> ConnectionResult {
|
||||||
network: NymNetworkDetails,
|
|
||||||
url: &Url,
|
|
||||||
client: &ApiClient,
|
|
||||||
) -> ConnectionResult {
|
|
||||||
let result = match timeout(
|
let result = match timeout(
|
||||||
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
|
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
|
||||||
client.get_cached_mixnodes(),
|
client.get_cached_mixnodes(),
|
||||||
@@ -153,15 +161,21 @@ async fn test_api_connection(
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(Ok(_)) => {
|
Ok(Ok(_)) => {
|
||||||
log::debug!("Checking: api_url: {url}: {}", "success".green());
|
log::debug!("Checking: api_url: {network}: {url}: {}", "success".green());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
|
log::debug!(
|
||||||
|
"Checking: api_url: {network}: {url}: {}: {e}",
|
||||||
|
"failed".red()
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
|
log::debug!(
|
||||||
|
"Checking: api_url: {network}: {url}: {}: {e}",
|
||||||
|
"failed".red()
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -169,8 +183,8 @@ async fn test_api_connection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ClientForConnectionTest {
|
enum ClientForConnectionTest {
|
||||||
Nymd(NymNetworkDetails, Url, Box<NymdClient<QueryNymdClient>>),
|
Nymd(Network, Url, Box<NymdClient<QueryNymdClient>>),
|
||||||
Api(NymNetworkDetails, Url, ApiClient),
|
Api(Network, Url, ApiClient),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientForConnectionTest {
|
impl ClientForConnectionTest {
|
||||||
@@ -203,12 +217,12 @@ impl fmt::Display for UrlType {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ConnectionResult {
|
enum ConnectionResult {
|
||||||
Nymd(NymNetworkDetails, Url, bool),
|
Nymd(Network, Url, bool),
|
||||||
Api(NymNetworkDetails, Url, bool),
|
Api(Network, Url, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectionResult {
|
impl ConnectionResult {
|
||||||
fn result(&self) -> (&NymNetworkDetails, &Url, &bool) {
|
fn result(&self) -> (&Network, &Url, &bool) {
|
||||||
match self {
|
match self {
|
||||||
ConnectionResult::Nymd(network, url, result)
|
ConnectionResult::Nymd(network, url, result)
|
||||||
| ConnectionResult::Api(network, url, result) => (network, url, result),
|
| ConnectionResult::Api(network, url, result) => (network, url, result),
|
||||||
@@ -225,8 +239,11 @@ impl ConnectionResult {
|
|||||||
|
|
||||||
impl fmt::Display for ConnectionResult {
|
impl fmt::Display for ConnectionResult {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let (_network, url, result) = self.result();
|
let (network, url, result) = self.result();
|
||||||
let url_type = self.url_type();
|
let url_type = self.url_type();
|
||||||
write!(f, "{url}: {url_type}: connection is successful: {result}")
|
write!(
|
||||||
|
f,
|
||||||
|
"{network}: {url}: {url_type}: connection is successful: {result}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use cosmrs::rpc::{self, HttpClient, Order};
|
|||||||
use cosmrs::tendermint::abci::Code as AbciCode;
|
use cosmrs::tendermint::abci::Code as AbciCode;
|
||||||
use cosmrs::tendermint::abci::Transaction;
|
use cosmrs::tendermint::abci::Transaction;
|
||||||
use cosmrs::tendermint::{abci, block, chain};
|
use cosmrs::tendermint::{abci, block, chain};
|
||||||
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Tx};
|
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Denom, Tx};
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
@@ -121,7 +121,7 @@ pub trait CosmWasmClient: rpc::Client {
|
|||||||
async fn get_balance(
|
async fn get_balance(
|
||||||
&self,
|
&self,
|
||||||
address: &AccountId,
|
address: &AccountId,
|
||||||
search_denom: String,
|
search_denom: Denom,
|
||||||
) -> Result<Option<Coin>, NymdError> {
|
) -> Result<Option<Coin>, NymdError> {
|
||||||
let path = Some("/cosmos.bank.v1beta1.Query/Balance".parse().unwrap());
|
let path = Some("/cosmos.bank.v1beta1.Query/Balance".parse().unwrap());
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ use crate::nymd::{Coin, GasAdjustable, GasPrice, TxResponse};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cosmrs::bank::MsgSend;
|
use cosmrs::bank::MsgSend;
|
||||||
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
||||||
use cosmrs::feegrant::{
|
|
||||||
AllowedMsgAllowance, BasicAllowance, MsgGrantAllowance, MsgRevokeAllowance,
|
|
||||||
};
|
|
||||||
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
|
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
|
||||||
use cosmrs::rpc::endpoint::broadcast;
|
use cosmrs::rpc::endpoint::broadcast;
|
||||||
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
|
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
|
||||||
@@ -26,7 +23,7 @@ use serde::Serialize;
|
|||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::Duration;
|
||||||
|
|
||||||
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
||||||
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
@@ -423,63 +420,6 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
|||||||
.check_response()
|
.check_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
async fn grant_allowance(
|
|
||||||
&self,
|
|
||||||
granter: &AccountId,
|
|
||||||
grantee: &AccountId,
|
|
||||||
spend_limit: Vec<Coin>,
|
|
||||||
expiration: Option<SystemTime>,
|
|
||||||
allowed_messages: Vec<String>,
|
|
||||||
fee: Fee,
|
|
||||||
memo: impl Into<String> + Send + 'static,
|
|
||||||
) -> Result<TxResponse, NymdError> {
|
|
||||||
let basic_allowance = BasicAllowance {
|
|
||||||
spend_limit: spend_limit.into_iter().map(Into::into).collect(),
|
|
||||||
expiration,
|
|
||||||
}
|
|
||||||
.to_any()
|
|
||||||
.map_err(|_| NymdError::SerializationError("BasicAllowance".to_owned()))?;
|
|
||||||
|
|
||||||
let allowed_msg_allowance = AllowedMsgAllowance {
|
|
||||||
allowance: Some(basic_allowance),
|
|
||||||
allowed_messages,
|
|
||||||
}
|
|
||||||
.to_any()
|
|
||||||
.map_err(|_| NymdError::SerializationError("AllowedMsgAllowance".to_owned()))?;
|
|
||||||
|
|
||||||
let grant_allowance_msg = MsgGrantAllowance {
|
|
||||||
granter: granter.to_owned(),
|
|
||||||
grantee: grantee.to_owned(),
|
|
||||||
allowance: Some(allowed_msg_allowance),
|
|
||||||
}
|
|
||||||
.to_any()
|
|
||||||
.map_err(|_| NymdError::SerializationError("MsgGrantAllowance".to_owned()))?;
|
|
||||||
|
|
||||||
self.sign_and_broadcast(granter, vec![grant_allowance_msg], fee, memo)
|
|
||||||
.await?
|
|
||||||
.check_response()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn revoke_allowance(
|
|
||||||
&self,
|
|
||||||
granter: &AccountId,
|
|
||||||
grantee: &AccountId,
|
|
||||||
fee: Fee,
|
|
||||||
memo: impl Into<String> + Send + 'static,
|
|
||||||
) -> Result<TxResponse, NymdError> {
|
|
||||||
let revoke_allowance_msg = MsgRevokeAllowance {
|
|
||||||
granter: granter.to_owned(),
|
|
||||||
grantee: grantee.to_owned(),
|
|
||||||
}
|
|
||||||
.to_any()
|
|
||||||
.map_err(|_| NymdError::SerializationError("MsgRevokeAllowance".to_owned()))?;
|
|
||||||
|
|
||||||
self.sign_and_broadcast(granter, vec![revoke_allowance_msg], fee, memo)
|
|
||||||
.await?
|
|
||||||
.check_response()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delegate_tokens(
|
async fn delegate_tokens(
|
||||||
&self,
|
&self,
|
||||||
delegator_address: &AccountId,
|
delegator_address: &AccountId,
|
||||||
@@ -574,10 +514,10 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
|||||||
let fee = match fee {
|
let fee = match fee {
|
||||||
Fee::Manual(fee) => fee,
|
Fee::Manual(fee) => fee,
|
||||||
Fee::Auto(multiplier) => auto_fee(multiplier).await?,
|
Fee::Auto(multiplier) => auto_fee(multiplier).await?,
|
||||||
Fee::PayerGranterAuto(auto_feegrant) => {
|
Fee::PayerGranterAuto(multiplier, payer, granter) => {
|
||||||
let mut fee = auto_fee(auto_feegrant.gas_adjustment).await?;
|
let mut fee = auto_fee(multiplier).await?;
|
||||||
fee.payer = auto_feegrant.payer;
|
fee.payer = payer;
|
||||||
fee.granter = auto_feegrant.granter;
|
fee.granter = granter;
|
||||||
fee
|
fee
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ impl TryFrom<ProtoContractCodeHistoryEntry> for ContractCodeHistoryEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct GasInfo {
|
pub struct GasInfo {
|
||||||
/// GasWanted is the maximum units of work we allow this tx to perform.
|
/// GasWanted is the maximum units of work we allow this tx to perform.
|
||||||
pub gas_wanted: Gas,
|
pub gas_wanted: Gas,
|
||||||
@@ -645,7 +645,7 @@ impl InstantiateOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub struct InstantiateResult {
|
pub struct InstantiateResult {
|
||||||
/// The address of the newly instantiated contract
|
/// The address of the newly instantiated contract
|
||||||
pub contract_address: AccountId,
|
pub contract_address: AccountId,
|
||||||
@@ -658,7 +658,7 @@ pub struct InstantiateResult {
|
|||||||
pub gas_info: GasInfo,
|
pub gas_info: GasInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub struct ChangeAdminResult {
|
pub struct ChangeAdminResult {
|
||||||
pub logs: Vec<Log>,
|
pub logs: Vec<Log>,
|
||||||
|
|
||||||
@@ -668,7 +668,7 @@ pub struct ChangeAdminResult {
|
|||||||
pub gas_info: GasInfo,
|
pub gas_info: GasInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub struct MigrateResult {
|
pub struct MigrateResult {
|
||||||
pub logs: Vec<Log>,
|
pub logs: Vec<Log>,
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ pub struct MigrateResult {
|
|||||||
pub gas_info: GasInfo,
|
pub gas_info: GasInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub struct ExecuteResult {
|
pub struct ExecuteResult {
|
||||||
pub logs: Vec<Log>,
|
pub logs: Vec<Log>,
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::nymd::Coin;
|
|
||||||
use crate::nymd::Gas;
|
use crate::nymd::Gas;
|
||||||
use cosmrs::{tx, AccountId};
|
use cosmrs::{tx, AccountId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
|
|
||||||
pub mod gas_price;
|
pub mod gas_price;
|
||||||
|
|
||||||
@@ -13,74 +11,11 @@ pub type GasAdjustment = f32;
|
|||||||
|
|
||||||
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
|
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct AutoFeeGrant {
|
|
||||||
pub gas_adjustment: Option<GasAdjustment>,
|
|
||||||
pub payer: Option<AccountId>,
|
|
||||||
pub granter: Option<AccountId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for AutoFeeGrant {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
if let Some(gas_adjustment) = self.gas_adjustment {
|
|
||||||
write!(f, "Feegrant in auto mode with {gas_adjustment} simulated multiplier with {:?} payer and {:?} granter", self.payer, self.granter)
|
|
||||||
} else {
|
|
||||||
write!(f, "Feegrant in auto mode with no custom simulated multiplier with {:?} payer and {:?} granter", self.payer, self.granter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum Fee {
|
pub enum Fee {
|
||||||
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
|
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
|
||||||
Auto(Option<GasAdjustment>),
|
Auto(Option<GasAdjustment>),
|
||||||
PayerGranterAuto(AutoFeeGrant),
|
PayerGranterAuto(Option<GasAdjustment>, Option<AccountId>, Option<AccountId>),
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Fee {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Fee::Manual(fee) => {
|
|
||||||
write!(f, "Fee in manual mode with ")?;
|
|
||||||
for fee in &fee.amount {
|
|
||||||
write!(f, "{}{} paid in fees, ", fee.amount, fee.denom)?;
|
|
||||||
}
|
|
||||||
write!(f, "{} set as gas limit, ", fee.gas_limit)?;
|
|
||||||
if let Some(payer) = &fee.payer {
|
|
||||||
write!(f, "{payer} set as payer, ")?;
|
|
||||||
}
|
|
||||||
if let Some(granter) = &fee.granter {
|
|
||||||
write!(f, "{granter} set as granter")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Fee::Auto(Some(multiplier)) => {
|
|
||||||
write!(f, "Fee in auto mode with {multiplier} simulated multiplier")
|
|
||||||
}
|
|
||||||
Fee::Auto(None) => write!(f, "Fee in auto mode with no custom simulated multiplier"),
|
|
||||||
Fee::PayerGranterAuto(auto_feegrant) => write!(f, "{}", auto_feegrant),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fee {
|
|
||||||
pub fn new_payer_granter_auto(
|
|
||||||
gas_adjustment: Option<GasAdjustment>,
|
|
||||||
payer: Option<AccountId>,
|
|
||||||
granter: Option<AccountId>,
|
|
||||||
) -> Self {
|
|
||||||
Fee::PayerGranterAuto(AutoFeeGrant {
|
|
||||||
gas_adjustment,
|
|
||||||
payer,
|
|
||||||
granter,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn try_get_manual_amount(&self) -> Option<Vec<Coin>> {
|
|
||||||
match self {
|
|
||||||
Fee::Manual(tx_fee) => Some(tx_fee.amount.iter().cloned().map(Into::into).collect()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tx::Fee> for Fee {
|
impl From<tx::Fee> for Fee {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::nymd::error::NymdError;
|
|
||||||
use crate::nymd::{CosmWasmClient, NymdClient};
|
|
||||||
|
|
||||||
use coconut_bandwidth_contract_common::msg::QueryMsg;
|
|
||||||
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait CoconutBandwidthQueryClient {
|
|
||||||
async fn get_spent_credential(
|
|
||||||
&self,
|
|
||||||
blinded_serial_number: String,
|
|
||||||
) -> Result<SpendCredentialResponse, NymdError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<C: CosmWasmClient + Sync + Send> CoconutBandwidthQueryClient for NymdClient<C> {
|
|
||||||
async fn get_spent_credential(
|
|
||||||
&self,
|
|
||||||
blinded_serial_number: String,
|
|
||||||
) -> Result<SpendCredentialResponse, NymdError> {
|
|
||||||
let request = QueryMsg::GetSpentCredential {
|
|
||||||
blinded_serial_number,
|
|
||||||
};
|
|
||||||
self.client
|
|
||||||
.query_contract_smart(self.coconut_bandwidth_contract_address(), &request)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-34
@@ -5,7 +5,6 @@ pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
|
|||||||
use crate::nymd::cosmwasm_client::types::ExecuteResult;
|
use crate::nymd::cosmwasm_client::types::ExecuteResult;
|
||||||
use crate::nymd::error::NymdError;
|
use crate::nymd::error::NymdError;
|
||||||
use crate::nymd::{Coin, Fee, NymdClient};
|
use crate::nymd::{Coin, Fee, NymdClient};
|
||||||
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialData;
|
|
||||||
use coconut_bandwidth_contract_common::{deposit::DepositData, msg::ExecuteMsg};
|
use coconut_bandwidth_contract_common::{deposit::DepositData, msg::ExecuteMsg};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -20,13 +19,6 @@ pub trait CoconutBandwidthSigningClient {
|
|||||||
encryption_key: String,
|
encryption_key: String,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
async fn spend_credential(
|
|
||||||
&self,
|
|
||||||
funds: Coin,
|
|
||||||
blinded_serial_number: String,
|
|
||||||
gateway_cosmos_address: String,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -54,30 +46,4 @@ impl<C: SigningCosmWasmClient + Sync + Send> CoconutBandwidthSigningClient for N
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
async fn spend_credential(
|
|
||||||
&self,
|
|
||||||
funds: Coin,
|
|
||||||
blinded_serial_number: String,
|
|
||||||
gateway_cosmos_address: String,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
|
||||||
let req = ExecuteMsg::SpendCredential {
|
|
||||||
data: SpendCredentialData::new(
|
|
||||||
funds.into(),
|
|
||||||
blinded_serial_number,
|
|
||||||
gateway_cosmos_address,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
self.client
|
|
||||||
.execute(
|
|
||||||
self.address(),
|
|
||||||
self.coconut_bandwidth_contract_address(),
|
|
||||||
&req,
|
|
||||||
fee,
|
|
||||||
"CoconutBandwidth::SpendCredential",
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,387 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
|
|
||||||
use crate::nymd::error::NymdError;
|
|
||||||
use crate::nymd::NymdClient;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use cosmrs::AccountId;
|
|
||||||
use mixnet_contract_common::delegation::{MixNodeDelegationResponse, OwnerProxySubKey};
|
|
||||||
use mixnet_contract_common::mixnode::{
|
|
||||||
MixNodeDetails, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
|
|
||||||
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
|
|
||||||
};
|
|
||||||
use mixnet_contract_common::reward_params::{Performance, RewardingParams};
|
|
||||||
use mixnet_contract_common::rewarding::{
|
|
||||||
EstimatedCurrentEpochRewardResponse, PendingRewardResponse,
|
|
||||||
};
|
|
||||||
use mixnet_contract_common::{
|
|
||||||
delegation, ContractBuildInformation, ContractState, ContractStateParams,
|
|
||||||
CurrentIntervalResponse, EpochEventId, GatewayBondResponse, GatewayOwnershipResponse,
|
|
||||||
IdentityKey, IntervalEventId, LayerDistribution, MixOwnershipResponse, MixnodeDetailsResponse,
|
|
||||||
NodeId, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
|
|
||||||
PagedMixNodeDelegationsResponse, PagedMixnodeBondsResponse, PagedRewardedSetResponse,
|
|
||||||
PendingEpochEventsResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
|
|
||||||
};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait MixnetQueryClient {
|
|
||||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NymdError>
|
|
||||||
where
|
|
||||||
for<'a> T: Deserialize<'a>;
|
|
||||||
|
|
||||||
// state/sys-params-related
|
|
||||||
|
|
||||||
async fn get_mixnet_contract_version(&self) -> Result<ContractBuildInformation, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetContractVersion {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_rewarding_validator_address(&self) -> Result<AccountId, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetRewardingValidatorAddress {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnet_contract_settings(&self) -> Result<ContractStateParams, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetStateParams {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnet_contract_state(&self) -> Result<ContractState, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetState {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_rewarding_parameters(&self) -> Result<RewardingParams, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetRewardingParams {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_current_interval_details(&self) -> Result<CurrentIntervalResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetCurrentIntervalDetails {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_rewarded_set_paged(
|
|
||||||
&self,
|
|
||||||
start_after: Option<NodeId>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
) -> Result<PagedRewardedSetResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSet { limit, start_after })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// mixnode-related:
|
|
||||||
|
|
||||||
async fn get_mixnode_bonds_paged(
|
|
||||||
&self,
|
|
||||||
limit: Option<u32>,
|
|
||||||
start_after: Option<NodeId>,
|
|
||||||
) -> Result<PagedMixnodeBondsResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnodes_detailed_paged(
|
|
||||||
&self,
|
|
||||||
limit: Option<u32>,
|
|
||||||
start_after: Option<NodeId>,
|
|
||||||
) -> Result<PagedMixnodesDetailsResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_unbonded_paged(
|
|
||||||
&self,
|
|
||||||
limit: Option<u32>,
|
|
||||||
start_after: Option<NodeId>,
|
|
||||||
) -> Result<PagedUnbondedMixnodesResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_unbonded_by_owner_paged(
|
|
||||||
&self,
|
|
||||||
owner: &AccountId,
|
|
||||||
limit: Option<u32>,
|
|
||||||
start_after: Option<NodeId>,
|
|
||||||
) -> Result<PagedUnbondedMixnodesResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner {
|
|
||||||
owner: owner.to_string(),
|
|
||||||
limit,
|
|
||||||
start_after,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_unbonded_by_identity_paged(
|
|
||||||
&self,
|
|
||||||
identity_key: String,
|
|
||||||
limit: Option<u32>,
|
|
||||||
start_after: Option<NodeId>,
|
|
||||||
) -> Result<PagedUnbondedMixnodesResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
|
|
||||||
identity_key,
|
|
||||||
limit,
|
|
||||||
start_after,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_owned_mixnode(
|
|
||||||
&self,
|
|
||||||
address: &AccountId,
|
|
||||||
) -> Result<MixOwnershipResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetOwnedMixnode {
|
|
||||||
address: address.to_string(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnode_details(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<MixnodeDetailsResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnode_rewarding_details(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<MixnodeRewardingDetailsResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnode_stake_saturation(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<StakeSaturationResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_unbonded_mixnode_information(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<UnbondedMixnodeResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_layer_distribution(&self) -> Result<LayerDistribution, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetLayerDistribution {})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// gateway-related:
|
|
||||||
|
|
||||||
async fn get_gateways_paged(
|
|
||||||
&self,
|
|
||||||
start_after: Option<IdentityKey>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
) -> Result<PagedGatewayResponse, NymdError> {
|
|
||||||
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, NymdError> {
|
|
||||||
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, NymdError> {
|
|
||||||
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: NodeId,
|
|
||||||
start_after: Option<String>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
) -> Result<PagedMixNodeDelegationsResponse, NymdError> {
|
|
||||||
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: String,
|
|
||||||
start_after: Option<(NodeId, OwnerProxySubKey)>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
) -> Result<PagedDelegatorDelegationsResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations {
|
|
||||||
delegator,
|
|
||||||
start_after,
|
|
||||||
limit,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks value of delegation of given client towards particular mixnode.
|
|
||||||
async fn get_delegation_details(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
delegator: &AccountId,
|
|
||||||
proxy: Option<String>,
|
|
||||||
) -> Result<MixNodeDelegationResponse, NymdError> {
|
|
||||||
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, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetAllDelegations { start_after, limit })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// rewards related
|
|
||||||
async fn get_pending_operator_reward(
|
|
||||||
&self,
|
|
||||||
operator: &AccountId,
|
|
||||||
) -> Result<PendingRewardResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingOperatorReward {
|
|
||||||
address: operator.to_string(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_pending_mixnode_operator_reward(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<PendingRewardResponse, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_pending_delegator_reward(
|
|
||||||
&self,
|
|
||||||
delegator: &AccountId,
|
|
||||||
mix_id: NodeId,
|
|
||||||
proxy: Option<String>,
|
|
||||||
) -> Result<PendingRewardResponse, NymdError> {
|
|
||||||
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: NodeId,
|
|
||||||
estimated_performance: Performance,
|
|
||||||
) -> Result<EstimatedCurrentEpochRewardResponse, NymdError> {
|
|
||||||
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: NodeId,
|
|
||||||
proxy: Option<String>,
|
|
||||||
estimated_performance: Performance,
|
|
||||||
) -> Result<EstimatedCurrentEpochRewardResponse, NymdError> {
|
|
||||||
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, NymdError> {
|
|
||||||
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, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetPendingIntervalEvents { start_after, limit })
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mixnode_details_by_identity(
|
|
||||||
&self,
|
|
||||||
mix_identity: IdentityKey,
|
|
||||||
) -> Result<Option<MixNodeDetails>, NymdError> {
|
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity {
|
|
||||||
mix_identity,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<C> MixnetQueryClient for NymdClient<C>
|
|
||||||
where
|
|
||||||
C: CosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NymdError>
|
|
||||||
where
|
|
||||||
for<'a> T: Deserialize<'a>,
|
|
||||||
{
|
|
||||||
self.client
|
|
||||||
.query_contract_smart(self.mixnet_contract_address(), &query)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<C> MixnetQueryClient for crate::Client<C>
|
|
||||||
where
|
|
||||||
C: CosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NymdError>
|
|
||||||
where
|
|
||||||
for<'a> T: Deserialize<'a>,
|
|
||||||
{
|
|
||||||
self.nymd.query_mixnet_contract(query).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,496 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::nymd::coin::Coin;
|
|
||||||
pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
|
|
||||||
use crate::nymd::cosmwasm_client::types::ExecuteResult;
|
|
||||||
use crate::nymd::error::NymdError;
|
|
||||||
use crate::nymd::{Fee, NymdClient, SigningCosmWasmClient};
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use cosmrs::AccountId;
|
|
||||||
use mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
|
||||||
use mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
|
|
||||||
use mixnet_contract_common::{
|
|
||||||
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait MixnetSigningClient {
|
|
||||||
async fn execute_mixnet_contract(
|
|
||||||
&self,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
msg: MixnetExecuteMsg,
|
|
||||||
funds: Vec<Coin>,
|
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
|
||||||
|
|
||||||
// state/sys-params-related
|
|
||||||
|
|
||||||
async fn update_rewarding_validator_address(
|
|
||||||
&self,
|
|
||||||
address: AccountId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateRewardingValidatorAddress {
|
|
||||||
address: address.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_contract_state_params(
|
|
||||||
&self,
|
|
||||||
updated_parameters: ContractStateParams,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateContractStateParams { updated_parameters },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_active_set_size(
|
|
||||||
&self,
|
|
||||||
active_set_size: u32,
|
|
||||||
force_immediately: bool,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateActiveSetSize {
|
|
||||||
active_set_size,
|
|
||||||
force_immediately,
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_rewarding_parameters(
|
|
||||||
&self,
|
|
||||||
updated_params: IntervalRewardingParamsUpdate,
|
|
||||||
force_immediately: bool,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateRewardingParams {
|
|
||||||
updated_params,
|
|
||||||
force_immediately,
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_interval_config(
|
|
||||||
&self,
|
|
||||||
epochs_in_interval: u32,
|
|
||||||
epoch_duration_secs: u64,
|
|
||||||
force_immediately: bool,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateIntervalConfig {
|
|
||||||
epochs_in_interval,
|
|
||||||
epoch_duration_secs,
|
|
||||||
force_immediately,
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn advance_current_epoch(
|
|
||||||
&self,
|
|
||||||
new_rewarded_set: Vec<NodeId>,
|
|
||||||
expected_active_set_size: u32,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::AdvanceCurrentEpoch {
|
|
||||||
new_rewarded_set,
|
|
||||||
expected_active_set_size,
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn reconcile_epoch_events(
|
|
||||||
&self,
|
|
||||||
limit: Option<u32>,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::ReconcileEpochEvents { limit },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// mixnode-related:
|
|
||||||
|
|
||||||
async fn bond_mixnode(
|
|
||||||
&self,
|
|
||||||
mix_node: MixNode,
|
|
||||||
cost_params: MixNodeCostParams,
|
|
||||||
owner_signature: String,
|
|
||||||
pledge: Coin,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::BondMixnode {
|
|
||||||
mix_node,
|
|
||||||
cost_params,
|
|
||||||
owner_signature,
|
|
||||||
},
|
|
||||||
vec![pledge],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn bond_mixnode_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
mix_node: MixNode,
|
|
||||||
cost_params: MixNodeCostParams,
|
|
||||||
owner_signature: String,
|
|
||||||
pledge: Coin,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::BondMixnodeOnBehalf {
|
|
||||||
mix_node,
|
|
||||||
cost_params,
|
|
||||||
owner_signature,
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![pledge],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondMixnode {}, vec![])
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn unbond_mixnode_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UnbondMixnodeOnBehalf {
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_mixnode_cost_params(
|
|
||||||
&self,
|
|
||||||
new_costs: MixNodeCostParams,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_mixnode_cost_params_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
new_costs: MixNodeCostParams,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateMixnodeCostParamsOnBehalf {
|
|
||||||
new_costs,
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_mixnode_config(
|
|
||||||
&self,
|
|
||||||
new_config: MixNodeConfigUpdate,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateMixnodeConfig { new_config },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_mixnode_config_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
new_config: MixNodeConfigUpdate,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UpdateMixnodeConfigOnBehalf {
|
|
||||||
new_config,
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// gateway-related:
|
|
||||||
|
|
||||||
async fn bond_gateway(
|
|
||||||
&self,
|
|
||||||
gateway: Gateway,
|
|
||||||
owner_signature: String,
|
|
||||||
pledge: Coin,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::BondGateway {
|
|
||||||
gateway,
|
|
||||||
owner_signature,
|
|
||||||
},
|
|
||||||
vec![pledge],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn bond_gateway_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
gateway: Gateway,
|
|
||||||
owner_signature: String,
|
|
||||||
pledge: Coin,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::BondGatewayOnBehalf {
|
|
||||||
gateway,
|
|
||||||
owner_signature,
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![pledge],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn unbond_gateway(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondGateway {}, vec![])
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn unbond_gateway_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UnbondGatewayOnBehalf {
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// delegation-related:
|
|
||||||
|
|
||||||
async fn delegate_to_mixnode(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
amount: Coin,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::DelegateToMixnode { mix_id },
|
|
||||||
vec![amount],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delegate_to_mixnode_on_behalf(
|
|
||||||
&self,
|
|
||||||
delegate: AccountId,
|
|
||||||
mix_id: NodeId,
|
|
||||||
amount: Coin,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::DelegateToMixnodeOnBehalf {
|
|
||||||
mix_id,
|
|
||||||
delegate: delegate.to_string(),
|
|
||||||
},
|
|
||||||
vec![amount],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn undelegate_from_mixnode(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UndelegateFromMixnode { mix_id },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn undelegate_to_mixnode_on_behalf(
|
|
||||||
&self,
|
|
||||||
delegate: AccountId,
|
|
||||||
mix_id: NodeId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf {
|
|
||||||
mix_id,
|
|
||||||
delegate: delegate.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// reward-related
|
|
||||||
|
|
||||||
async fn reward_mixnode(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
performance: Performance,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::RewardMixnode {
|
|
||||||
mix_id,
|
|
||||||
performance,
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn withdraw_operator_reward(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::WithdrawOperatorReward {}, vec![])
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn withdraw_operator_reward_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::WithdrawOperatorRewardOnBehalf {
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn withdraw_delegator_reward(
|
|
||||||
&self,
|
|
||||||
mix_id: NodeId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn withdraw_delegator_reward_on_behalf(
|
|
||||||
&self,
|
|
||||||
owner: AccountId,
|
|
||||||
mix_id: NodeId,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_mixnet_contract(
|
|
||||||
fee,
|
|
||||||
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf {
|
|
||||||
mix_id,
|
|
||||||
owner: owner.to_string(),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<C> MixnetSigningClient for NymdClient<C>
|
|
||||||
where
|
|
||||||
C: SigningCosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
async fn execute_mixnet_contract(
|
|
||||||
&self,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
msg: MixnetExecuteMsg,
|
|
||||||
funds: Vec<Coin>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
|
||||||
let memo = msg.default_memo();
|
|
||||||
self.client
|
|
||||||
.execute(
|
|
||||||
self.address(),
|
|
||||||
self.mixnet_contract_address(),
|
|
||||||
&msg,
|
|
||||||
fee,
|
|
||||||
memo,
|
|
||||||
funds,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<C> MixnetSigningClient for crate::Client<C>
|
|
||||||
where
|
|
||||||
C: SigningCosmWasmClient + Sync + Send,
|
|
||||||
{
|
|
||||||
async fn execute_mixnet_contract(
|
|
||||||
&self,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
msg: MixnetExecuteMsg,
|
|
||||||
funds: Vec<Coin>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.nymd.execute_mixnet_contract(fee, msg, funds).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
mod coconut_bandwidth_query_client;
|
|
||||||
mod coconut_bandwidth_signing_client;
|
mod coconut_bandwidth_signing_client;
|
||||||
mod mixnet_query_client;
|
|
||||||
mod mixnet_signing_client;
|
|
||||||
mod multisig_query_client;
|
mod multisig_query_client;
|
||||||
mod multisig_signing_client;
|
mod multisig_signing_client;
|
||||||
mod vesting_query_client;
|
mod vesting_query_client;
|
||||||
mod vesting_signing_client;
|
mod vesting_signing_client;
|
||||||
|
|
||||||
pub use coconut_bandwidth_query_client::CoconutBandwidthQueryClient;
|
|
||||||
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
|
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
|
||||||
pub use mixnet_query_client::MixnetQueryClient;
|
pub use multisig_query_client::QueryClient;
|
||||||
pub use mixnet_signing_client::MixnetSigningClient;
|
|
||||||
pub use multisig_query_client::MultisigQueryClient;
|
|
||||||
pub use multisig_signing_client::MultisigSigningClient;
|
pub use multisig_signing_client::MultisigSigningClient;
|
||||||
pub use vesting_query_client::VestingQueryClient;
|
pub use vesting_query_client::VestingQueryClient;
|
||||||
pub use vesting_signing_client::VestingSigningClient;
|
pub use vesting_signing_client::VestingSigningClient;
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ use multisig_contract_common::msg::{ProposalResponse, QueryMsg};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait MultisigQueryClient {
|
pub trait QueryClient {
|
||||||
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError>;
|
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<C: CosmWasmClient + Sync + Send> MultisigQueryClient for NymdClient<C> {
|
impl<C: CosmWasmClient + Sync + Send> QueryClient for NymdClient<C> {
|
||||||
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError> {
|
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError> {
|
||||||
let request = QueryMsg::Proposal { proposal_id };
|
let request = QueryMsg::Proposal { proposal_id };
|
||||||
self.client
|
self.client
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use multisig_contract_common::msg::ExecuteMsg;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
|
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
|
||||||
use cw3::Vote;
|
use cw3::Vote;
|
||||||
|
use network_defaults::DEFAULT_NETWORK;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait MultisigSigningClient {
|
pub trait MultisigSigningClient {
|
||||||
@@ -48,10 +49,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
|
|||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
||||||
funds: Coin::new(
|
funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
|
||||||
voucher_value,
|
|
||||||
self.config.chain_details.mix_denom.base.clone(),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
|
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ use crate::nymd::error::NymdError;
|
|||||||
use crate::nymd::NymdClient;
|
use crate::nymd::NymdClient;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
|
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
|
||||||
use mixnet_contract_common::NodeId;
|
|
||||||
use vesting_contract::vesting::Account;
|
use vesting_contract::vesting::Account;
|
||||||
use vesting_contract_common::{
|
use vesting_contract_common::{
|
||||||
messages::QueryMsg as VestingQueryMsg, AllDelegationsResponse, DelegationTimesResponse,
|
messages::QueryMsg as VestingQueryMsg, OriginalVestingResponse, Period, PledgeData,
|
||||||
OriginalVestingResponse, Period, PledgeData, VestingDelegation,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -72,37 +70,6 @@ pub trait VestingQueryClient {
|
|||||||
&self,
|
&self,
|
||||||
vesting_account_address: &str,
|
vesting_account_address: &str,
|
||||||
) -> Result<Period, NymdError>;
|
) -> Result<Period, NymdError>;
|
||||||
|
|
||||||
async fn get_delegation_timestamps(
|
|
||||||
&self,
|
|
||||||
address: &str,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<DelegationTimesResponse, NymdError>;
|
|
||||||
|
|
||||||
async fn get_all_vesting_delegations_paged(
|
|
||||||
&self,
|
|
||||||
start_after: Option<(u32, NodeId, u64)>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
) -> Result<AllDelegationsResponse, NymdError>;
|
|
||||||
|
|
||||||
async fn get_all_vesting_delegations(&self) -> Result<Vec<VestingDelegation>, NymdError> {
|
|
||||||
let mut delegations = Vec::new();
|
|
||||||
let mut start_after = None;
|
|
||||||
loop {
|
|
||||||
let mut paged_response = self
|
|
||||||
.get_all_vesting_delegations_paged(start_after.take(), None)
|
|
||||||
.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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -265,29 +232,4 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
|
|||||||
.query_contract_smart(self.vesting_contract_address(), &request)
|
.query_contract_smart(self.vesting_contract_address(), &request)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_delegation_timestamps(
|
|
||||||
&self,
|
|
||||||
address: &str,
|
|
||||||
mix_id: NodeId,
|
|
||||||
) -> Result<DelegationTimesResponse, NymdError> {
|
|
||||||
let request = VestingQueryMsg::GetDelegationTimes {
|
|
||||||
address: address.to_string(),
|
|
||||||
mix_id,
|
|
||||||
};
|
|
||||||
self.client
|
|
||||||
.query_contract_smart(self.vesting_contract_address(), &request)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_all_vesting_delegations_paged(
|
|
||||||
&self,
|
|
||||||
start_after: Option<(u32, NodeId, u64)>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
) -> Result<AllDelegationsResponse, NymdError> {
|
|
||||||
let request = VestingQueryMsg::GetAllDelegations { start_after, limit };
|
|
||||||
self.client
|
|
||||||
.query_contract_smart(self.vesting_contract_address(), &request)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,28 +6,14 @@ use crate::nymd::cosmwasm_client::types::ExecuteResult;
|
|||||||
use crate::nymd::error::NymdError;
|
use crate::nymd::error::NymdError;
|
||||||
use crate::nymd::{Coin, Fee, NymdClient};
|
use crate::nymd::{Coin, Fee, NymdClient};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
use mixnet_contract_common::{Gateway, IdentityKey, IdentityKeyRef, MixNode};
|
||||||
use mixnet_contract_common::{Gateway, MixNode, NodeId};
|
|
||||||
use vesting_contract_common::messages::{ExecuteMsg as VestingExecuteMsg, VestingSpecification};
|
use vesting_contract_common::messages::{ExecuteMsg as VestingExecuteMsg, VestingSpecification};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait VestingSigningClient {
|
pub trait VestingSigningClient {
|
||||||
async fn execute_vesting_contract(
|
|
||||||
&self,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
msg: VestingExecuteMsg,
|
|
||||||
funds: Vec<Coin>,
|
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
|
||||||
|
|
||||||
async fn vesting_update_mixnode_cost_params(
|
|
||||||
&self,
|
|
||||||
new_costs: MixNodeCostParams,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
|
||||||
|
|
||||||
async fn vesting_update_mixnode_config(
|
async fn vesting_update_mixnode_config(
|
||||||
&self,
|
&self,
|
||||||
new_config: MixNodeConfigUpdate,
|
profix_margin_percent: u8,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
|
|
||||||
@@ -57,12 +43,10 @@ pub trait VestingSigningClient {
|
|||||||
async fn vesting_bond_mixnode(
|
async fn vesting_bond_mixnode(
|
||||||
&self,
|
&self,
|
||||||
mix_node: MixNode,
|
mix_node: MixNode,
|
||||||
cost_params: MixNodeCostParams,
|
|
||||||
owner_signature: &str,
|
owner_signature: &str,
|
||||||
pledge: Coin,
|
pledge: Coin,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
|
|
||||||
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>;
|
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>;
|
||||||
|
|
||||||
async fn vesting_track_unbond_mixnode(
|
async fn vesting_track_unbond_mixnode(
|
||||||
@@ -81,21 +65,21 @@ pub trait VestingSigningClient {
|
|||||||
async fn vesting_track_undelegation(
|
async fn vesting_track_undelegation(
|
||||||
&self,
|
&self,
|
||||||
address: &str,
|
address: &str,
|
||||||
mix_id: NodeId,
|
mix_identity: IdentityKey,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
|
|
||||||
async fn vesting_delegate_to_mixnode(
|
async fn vesting_delegate_to_mixnode<'a>(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
mix_identity: IdentityKeyRef<'a>,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
|
|
||||||
async fn vesting_undelegate_from_mixnode(
|
async fn vesting_undelegate_from_mixnode<'a>(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
mix_identity: IdentityKeyRef<'a>,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
|
|
||||||
@@ -111,46 +95,15 @@ pub trait VestingSigningClient {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient<C> {
|
impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient<C> {
|
||||||
async fn execute_vesting_contract(
|
|
||||||
&self,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
msg: VestingExecuteMsg,
|
|
||||||
funds: Vec<Coin>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
|
||||||
let memo = msg.name().to_string();
|
|
||||||
self.client
|
|
||||||
.execute(
|
|
||||||
self.address(),
|
|
||||||
self.vesting_contract_address(),
|
|
||||||
&msg,
|
|
||||||
fee,
|
|
||||||
memo,
|
|
||||||
funds,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn vesting_update_mixnode_cost_params(
|
|
||||||
&self,
|
|
||||||
new_costs: MixNodeCostParams,
|
|
||||||
fee: Option<Fee>,
|
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
|
||||||
self.execute_vesting_contract(
|
|
||||||
fee,
|
|
||||||
VestingExecuteMsg::UpdateMixnodeCostParams { new_costs },
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn vesting_update_mixnode_config(
|
async fn vesting_update_mixnode_config(
|
||||||
&self,
|
&self,
|
||||||
new_config: MixNodeConfigUpdate,
|
profit_margin_percent: u8,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
let req = VestingExecuteMsg::UpdateMixnodeConfig { new_config };
|
let req = VestingExecuteMsg::UpdateMixnodeConfig {
|
||||||
|
profit_margin_percent,
|
||||||
|
};
|
||||||
self.client
|
self.client
|
||||||
.execute(
|
.execute(
|
||||||
self.address(),
|
self.address(),
|
||||||
@@ -250,22 +203,26 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
|||||||
async fn vesting_bond_mixnode(
|
async fn vesting_bond_mixnode(
|
||||||
&self,
|
&self,
|
||||||
mix_node: MixNode,
|
mix_node: MixNode,
|
||||||
cost_params: MixNodeCostParams,
|
|
||||||
owner_signature: &str,
|
owner_signature: &str,
|
||||||
pledge: Coin,
|
pledge: Coin,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
self.execute_vesting_contract(
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
fee,
|
let req = VestingExecuteMsg::BondMixnode {
|
||||||
VestingExecuteMsg::BondMixnode {
|
mix_node,
|
||||||
mix_node,
|
owner_signature: owner_signature.to_string(),
|
||||||
cost_params,
|
amount: pledge.into(),
|
||||||
owner_signature: owner_signature.to_string(),
|
};
|
||||||
amount: pledge.into(),
|
self.client
|
||||||
},
|
.execute(
|
||||||
vec![],
|
self.address(),
|
||||||
)
|
self.vesting_contract_address(),
|
||||||
.await
|
&req,
|
||||||
|
fee,
|
||||||
|
"VestingContract::BondMixnode",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
|
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
|
||||||
@@ -305,7 +262,6 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn withdraw_vested_coins(
|
async fn withdraw_vested_coins(
|
||||||
&self,
|
&self,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
@@ -326,54 +282,72 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn vesting_track_undelegation(
|
async fn vesting_track_undelegation(
|
||||||
&self,
|
&self,
|
||||||
address: &str,
|
address: &str,
|
||||||
mix_id: NodeId,
|
mix_identity: IdentityKey,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
self.execute_vesting_contract(
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
fee,
|
let req = VestingExecuteMsg::TrackUndelegation {
|
||||||
VestingExecuteMsg::TrackUndelegation {
|
owner: address.to_string(),
|
||||||
owner: address.to_string(),
|
mix_identity,
|
||||||
mix_id,
|
amount: amount.into(),
|
||||||
amount: amount.into(),
|
};
|
||||||
},
|
self.client
|
||||||
vec![],
|
.execute(
|
||||||
)
|
self.address(),
|
||||||
.await
|
self.vesting_contract_address(),
|
||||||
|
&req,
|
||||||
|
fee,
|
||||||
|
"VestingContract::TrackUndelegation",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
async fn vesting_delegate_to_mixnode<'a>(
|
||||||
async fn vesting_delegate_to_mixnode(
|
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
mix_identity: IdentityKeyRef<'a>,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
self.execute_vesting_contract(
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
fee,
|
let req = VestingExecuteMsg::DelegateToMixnode {
|
||||||
VestingExecuteMsg::DelegateToMixnode {
|
mix_identity: mix_identity.into(),
|
||||||
mix_id,
|
amount: amount.into(),
|
||||||
amount: amount.into(),
|
};
|
||||||
},
|
self.client
|
||||||
vec![],
|
.execute(
|
||||||
)
|
self.address(),
|
||||||
.await
|
self.vesting_contract_address(),
|
||||||
|
&req,
|
||||||
|
fee,
|
||||||
|
"VestingContract::DelegateToMixnode",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn vesting_undelegate_from_mixnode(
|
async fn vesting_undelegate_from_mixnode<'a>(
|
||||||
&self,
|
&self,
|
||||||
mix_id: NodeId,
|
mix_identity: IdentityKeyRef<'a>,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
self.execute_vesting_contract(
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
fee,
|
let req = VestingExecuteMsg::UndelegateFromMixnode {
|
||||||
VestingExecuteMsg::UndelegateFromMixnode { mix_id },
|
mix_identity: mix_identity.into(),
|
||||||
vec![],
|
};
|
||||||
)
|
self.client
|
||||||
.await
|
.execute(
|
||||||
|
self.address(),
|
||||||
|
self.vesting_contract_address(),
|
||||||
|
&req,
|
||||||
|
fee,
|
||||||
|
"VestingContract::UndelegateFromMixnode",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_periodic_vesting_account(
|
async fn create_periodic_vesting_account(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
use crate::nymd::error::NymdError;
|
use crate::nymd::error::NymdError;
|
||||||
use config::defaults;
|
use config::defaults;
|
||||||
use cosmrs::bip32::{DerivationPath, XPrv};
|
use cosmrs::bip32::{DerivationPath, XPrv};
|
||||||
use cosmrs::crypto::secp256k1::{Signature, SigningKey};
|
use cosmrs::crypto::secp256k1::SigningKey;
|
||||||
use cosmrs::crypto::PublicKey;
|
use cosmrs::crypto::PublicKey;
|
||||||
use cosmrs::tx::SignDoc;
|
use cosmrs::tx::SignDoc;
|
||||||
use cosmrs::{tx, AccountId};
|
use cosmrs::{tx, AccountId};
|
||||||
@@ -72,7 +72,7 @@ impl DirectSecp256k1HdWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn derive_keypair(&self, hd_path: &DerivationPath) -> Result<Secp256k1Keypair, NymdError> {
|
fn derive_keypair(&self, hd_path: &DerivationPath) -> Result<Secp256k1Keypair, NymdError> {
|
||||||
let extended_private_key = XPrv::derive_from_path(self.seed, hd_path)?;
|
let extended_private_key = XPrv::derive_from_path(&self.seed, hd_path)?;
|
||||||
|
|
||||||
let private_key: SigningKey = extended_private_key.into();
|
let private_key: SigningKey = extended_private_key.into();
|
||||||
let public_key = private_key.public_key();
|
let public_key = private_key.public_key();
|
||||||
@@ -105,17 +105,6 @@ impl DirectSecp256k1HdWallet {
|
|||||||
self.secret.to_string()
|
self.secret.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_raw_with_account(
|
|
||||||
&self,
|
|
||||||
signer: &AccountData,
|
|
||||||
message: &[u8],
|
|
||||||
) -> Result<Signature, NymdError> {
|
|
||||||
signer
|
|
||||||
.private_key
|
|
||||||
.sign(message)
|
|
||||||
.map_err(|_| NymdError::SigningFailure)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign_direct_with_account(
|
pub fn sign_direct_with_account(
|
||||||
&self,
|
&self,
|
||||||
signer: &AccountData,
|
signer: &AccountData,
|
||||||
@@ -207,9 +196,8 @@ impl DirectSecp256k1HdWalletBuilder {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use network_defaults::NymNetworkDetails;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use network_defaults::all::Network::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generating_account_addresses() {
|
fn generating_account_addresses() {
|
||||||
@@ -219,22 +207,35 @@ mod tests {
|
|||||||
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
|
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
|
||||||
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
|
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
|
||||||
];
|
];
|
||||||
let prefix = NymNetworkDetails::new_mainnet()
|
let prefixes = vec![
|
||||||
.chain_details
|
MAINNET.bech32_prefix(),
|
||||||
.bech32_account_prefix;
|
SANDBOX.bech32_prefix(),
|
||||||
|
QA.bech32_prefix(),
|
||||||
let addrs = vec![
|
|
||||||
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
|
|
||||||
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
|
|
||||||
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
|
|
||||||
];
|
];
|
||||||
for (idx, mnemonic) in mnemonics.iter().enumerate() {
|
|
||||||
let wallet =
|
for prefix in prefixes {
|
||||||
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap()).unwrap();
|
let addrs = match prefix.as_ref() {
|
||||||
assert_eq!(
|
"nymt" => vec![
|
||||||
wallet.try_derive_accounts().unwrap()[0].address,
|
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
|
||||||
addrs[idx].parse().unwrap()
|
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
|
||||||
)
|
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
|
||||||
|
],
|
||||||
|
"n" => vec![
|
||||||
|
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
|
||||||
|
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
|
||||||
|
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
|
||||||
|
],
|
||||||
|
_ => panic!("Test needs to be updated with new bech32 prefix"),
|
||||||
|
};
|
||||||
|
for (idx, mnemonic) in mnemonics.iter().enumerate() {
|
||||||
|
let wallet =
|
||||||
|
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
wallet.try_derive_accounts().unwrap()[0].address,
|
||||||
|
addrs[idx].parse().unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user