Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f9bfb4bb4 |
+4
-4
@@ -19,10 +19,10 @@
|
|||||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
||||||
|
|
||||||
# JS rules:
|
# JS rules:
|
||||||
*.js @mmsinclair @fmtabbara
|
*.js @mmsinclair @fmtabbara @Aid19801
|
||||||
*.ts @mmsinclair @fmtabbara
|
*.ts @mmsinclair @fmtabbara @Aid19801
|
||||||
*.tsx @mmsinclair @fmtabbara
|
*.tsx @mmsinclair @fmtabbara @Aid19801
|
||||||
*.jsx @mmsinclair @fmtabbara
|
*.jsx @mmsinclair @fmtabbara @Aid19801
|
||||||
|
|
||||||
# Something looking like possible documentation rules:
|
# Something looking like possible documentation rules:
|
||||||
*.md @mfahampshire
|
*.md @mfahampshire
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -13,9 +13,9 @@ jobs:
|
|||||||
- name: Install rsync
|
- name: Install rsync
|
||||||
run: sudo apt-get install rsync
|
run: sudo apt-get install rsync
|
||||||
- uses: rlespinasse/github-slug-action@v3.x
|
- uses: rlespinasse/github-slug-action@v3.x
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: '16'
|
||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
@@ -41,13 +41,6 @@ jobs:
|
|||||||
command: test
|
command: test
|
||||||
args: --workspace --all-features
|
args: --workspace --all-features
|
||||||
|
|
||||||
- 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
|
- name: Check formatting
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
@@ -58,7 +51,7 @@ jobs:
|
|||||||
name: Clippy checks
|
name: Clippy checks
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
args: --workspace --all-features
|
args: --all-features
|
||||||
|
|
||||||
- name: Run clippy
|
- name: Run clippy
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
name: Nym Connect (rust)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths-ignore:
|
|
||||||
- 'explorer/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: [ self-hosted, custom-linux ]
|
|
||||||
env:
|
|
||||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
|
||||||
steps:
|
|
||||||
- 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 squashfs-tools libayatana-appindicator3-dev
|
|
||||||
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Install rust toolchain
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
|
||||||
override: true
|
|
||||||
components: rustfmt, clippy
|
|
||||||
|
|
||||||
- name: Build all binaries
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: build
|
|
||||||
args: --manifest-path nym-connect/Cargo.toml --workspace
|
|
||||||
|
|
||||||
- name: Run all tests
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: test
|
|
||||||
args: --manifest-path nym-connect/Cargo.toml --workspace
|
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --manifest-path nym-connect/Cargo.toml --all -- --check
|
|
||||||
|
|
||||||
- uses: actions-rs/clippy-check@v1
|
|
||||||
name: Clippy checks
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
args: --manifest-path nym-connect/Cargo.toml --workspace --all-features
|
|
||||||
|
|
||||||
- name: Run clippy
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: clippy
|
|
||||||
args: --manifest-path nym-connect/Cargo.toml --workspace --all-features -- -D warnings
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
name: Build release of Nym smart contracts
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: contracts
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
target: wasm32-unknown-unknown
|
|
||||||
override: true
|
|
||||||
components: rustfmt, clippy
|
|
||||||
|
|
||||||
- name: Build release contracts
|
|
||||||
run: RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
|
|
||||||
|
|
||||||
- name: Upload Mixnet Contract Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: mixnet_contract.wasm
|
|
||||||
path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
|
||||||
retention-days: 5
|
|
||||||
|
|
||||||
- name: Upload Vesting Contract Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: vesting_contract.wasm
|
|
||||||
path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
|
||||||
retention-days: 5
|
|
||||||
@@ -14,9 +14,9 @@ jobs:
|
|||||||
runs-on: custom-runner-linux
|
runs-on: custom-runner-linux
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: '16'
|
||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
- name: Run ESLint
|
- name: Run ESLint
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
name: CI for Network Explorer
|
name: CI for Network Explorer
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'explorer/**'
|
- 'explorer/**'
|
||||||
@@ -18,9 +17,9 @@ jobs:
|
|||||||
- name: Install rsync
|
- name: Install rsync
|
||||||
run: sudo apt-get install rsync
|
run: sudo apt-get install rsync
|
||||||
- uses: rlespinasse/github-slug-action@v3.x
|
- uses: rlespinasse/github-slug-action@v3.x
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: '16'
|
||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -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/"
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ name: Nightly builds
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '14 1 * * *'
|
- cron: '14 4 * * *'
|
||||||
jobs:
|
jobs:
|
||||||
matrix_prep:
|
matrix_prep:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -44,31 +44,12 @@ 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:
|
||||||
command: test
|
command: test
|
||||||
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 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
|
- name: Check formatting
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
@@ -94,9 +75,9 @@ jobs:
|
|||||||
command: clippy
|
command: clippy
|
||||||
args: --workspace --all-targets -- -D warnings
|
args: --workspace --all-targets -- -D warnings
|
||||||
|
|
||||||
- name: Reclaim some disk space
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
|
|||||||
@@ -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_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
|
||||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
|
||||||
uses: docker://keybaseio/client:stable-node
|
|
||||||
with:
|
|
||||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
name: Nightly builds on dispatch
|
|
||||||
|
|
||||||
on: workflow_dispatch
|
|
||||||
jobs:
|
|
||||||
notification:
|
|
||||||
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: "Notification test"
|
|
||||||
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_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
|
||||||
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,96 +0,0 @@
|
|||||||
name: Publish Nym Connect (MacOS)
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: nym-connect
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish-tauri:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [macos-latest]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Check the release tag starts with `nym-connect-`
|
|
||||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('Release tag did not start with nym-connect-...')
|
|
||||||
|
|
||||||
- name: Node v16
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
- name: Install the Apple developer certificate for code signing
|
|
||||||
env:
|
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
# create variables
|
|
||||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
|
||||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
||||||
|
|
||||||
# import certificate and provisioning profile from secrets
|
|
||||||
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
|
|
||||||
|
|
||||||
# create temporary keychain
|
|
||||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
||||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
||||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
||||||
|
|
||||||
# import certificate to keychain
|
|
||||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
||||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
||||||
|
|
||||||
- name: Create env file
|
|
||||||
uses: timheuer/base64-to-file@v1.1
|
|
||||||
with:
|
|
||||||
fileName: '.env'
|
|
||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
|
||||||
|
|
||||||
- name: Install app dependencies and build it
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
|
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
run: yarn && yarn build
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: nym-connect_1.0.0_x64.dmg
|
|
||||||
path: nym-connect/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- name: Clean up keychain
|
|
||||||
if: ${{ always() }}
|
|
||||||
run: |
|
|
||||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
nym-connect/target/release/bundle/dmg/*.dmg
|
|
||||||
nym-connect/target/release/bundle/macos/*.app.tar.gz*
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
name: Publish Nym Connect (Ubuntu)
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: nym-connect
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish-tauri:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [ubuntu-latest]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Tauri dependencies
|
|
||||||
run: >
|
|
||||||
sudo apt-get update &&
|
|
||||||
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
|
|
||||||
- name: Check the release tag starts with `nym-connect-`
|
|
||||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('Release tag did not start with nym-connect-...')
|
|
||||||
|
|
||||||
- name: Node v16
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
- name: Install app dependencies
|
|
||||||
run: yarn
|
|
||||||
- name: Create env file
|
|
||||||
uses: timheuer/base64-to-file@v1.1
|
|
||||||
with:
|
|
||||||
fileName: '.env'
|
|
||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
|
||||||
|
|
||||||
- name: Build app
|
|
||||||
run: yarn build
|
|
||||||
env:
|
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: nym-connect.AppImage.tar.gz
|
|
||||||
path: nym-connect/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
nym-connect/target/release/bundle/appimage/*.AppImage
|
|
||||||
nym-connect/target/release/bundle/appimage/*.AppImage.tar.gz*
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
name: Publish Nym Connect (Windows 10)
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: nym-connect
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish-tauri:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [windows10]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- name: Clean up first
|
|
||||||
continue-on-error: true
|
|
||||||
working-directory: .
|
|
||||||
run: |
|
|
||||||
cd ..
|
|
||||||
del /s /q /A:H nym
|
|
||||||
rmdir /s /q nym
|
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Check the release tag starts with `nym-connect-`
|
|
||||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('Release tag did not start with nym-connect-...')
|
|
||||||
|
|
||||||
- name: Import signing certificate
|
|
||||||
env:
|
|
||||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
|
||||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
New-Item -ItemType directory -Path certificate
|
|
||||||
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
|
|
||||||
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
|
|
||||||
Remove-Item -path certificate -include tempCert.txt
|
|
||||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
|
||||||
|
|
||||||
- name: Node v16
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
|
|
||||||
- name: Create env file
|
|
||||||
uses: timheuer/base64-to-file@v1.1
|
|
||||||
with:
|
|
||||||
fileName: '.env'
|
|
||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
|
||||||
|
|
||||||
- name: Install app dependencies
|
|
||||||
run: yarn
|
|
||||||
|
|
||||||
- name: Build and sign it
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
|
||||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
|
||||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
run: yarn build
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: nym-connect_1.0.0_x64_en-US.msi
|
|
||||||
path: nym-connect/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
nym-connect/target/release/bundle/msi/*.msi
|
|
||||||
nym-connect/target/release/bundle/msi/*.msi.zip*
|
|
||||||
@@ -17,9 +17,9 @@ jobs:
|
|||||||
- name: Install rsync
|
- name: Install rsync
|
||||||
run: sudo apt-get install rsync
|
run: sudo apt-get install rsync
|
||||||
- uses: rlespinasse/github-slug-action@v3.x
|
- uses: rlespinasse/github-slug-action@v3.x
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: '16'
|
||||||
- name: Install Yarn
|
- name: Install Yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
- run: yarn
|
- run: yarn
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
name: Publish Nym binaries
|
name: Publish Nym binaries
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
@@ -20,7 +18,7 @@ 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: |
|
||||||
@@ -37,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
|
||||||
@@ -63,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
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
name: Publish Nym Wallet (MacOS)
|
name: Publish Nym Wallet (MacOS)
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
@@ -20,16 +19,16 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Check the release tag starts with `nym-wallet-`
|
- name: Check the release tag starts with `nym-wallet-`
|
||||||
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false && github.event_name != 'workflow_dispatch'
|
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false
|
||||||
uses: actions/github-script@v3
|
uses: actions/github-script@v3
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
core.setFailed('Release tag did not start with nym-wallet-...')
|
core.setFailed('Release tag did not start with nym-wallet-...')
|
||||||
|
|
||||||
- name: Node v16
|
- name: Node v16
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16.x
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
@@ -56,12 +55,6 @@ jobs:
|
|||||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||||
|
|
||||||
- name: Create env file
|
|
||||||
uses: timheuer/base64-to-file@v1.1
|
|
||||||
with:
|
|
||||||
fileName: '.env'
|
|
||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
|
||||||
|
|
||||||
- name: Install app dependencies and build it
|
- name: Install app dependencies and build it
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -73,24 +66,17 @@ jobs:
|
|||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||||
run: yarn && yarn build
|
run: yarn && yarn build
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload to release based on tag name
|
||||||
uses: actions/upload-artifact@v3
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
name: nym-wallet.app.tar.gz
|
files: |
|
||||||
path: nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz
|
nym-wallet/target/release/bundle/dmg/*.dmg
|
||||||
retention-days: 5
|
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
|
||||||
|
|
||||||
- name: Clean up keychain
|
- name: Clean up keychain
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
run: |
|
run: |
|
||||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
nym-wallet/target/release/bundle/dmg/*.dmg
|
|
||||||
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
|
|
||||||
|
|||||||
@@ -30,26 +30,21 @@ jobs:
|
|||||||
core.setFailed('Release tag did not start with nym-wallet-...')
|
core.setFailed('Release tag did not start with nym-wallet-...')
|
||||||
|
|
||||||
- name: Node v16
|
- name: Node v16
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16.x
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
- name: Install app dependencies
|
- name: Install app dependencies
|
||||||
run: yarn
|
run: yarn
|
||||||
- name: Create env file
|
|
||||||
uses: timheuer/base64-to-file@v1.1
|
|
||||||
with:
|
|
||||||
fileName: '.env'
|
|
||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
|
||||||
|
|
||||||
- name: Build app
|
- name: Build app
|
||||||
run: yarn build
|
run: yarn build
|
||||||
env:
|
env:
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||||
- 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
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -45,21 +45,15 @@ jobs:
|
|||||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||||
|
|
||||||
- name: Node v16
|
- name: Node v16
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16.x
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
|
|
||||||
- name: Create env file
|
|
||||||
uses: timheuer/base64-to-file@v1.1
|
|
||||||
with:
|
|
||||||
fileName: '.env'
|
|
||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
|
||||||
|
|
||||||
- name: Install app dependencies
|
- name: Install app dependencies
|
||||||
run: yarn
|
run: yarn
|
||||||
|
|
||||||
@@ -71,6 +65,7 @@ jobs:
|
|||||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||||
run: yarn build
|
run: yarn build
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
- name: Upload to release based on tag name
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
name: Release Nym Wallet
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
nym_wallet_version:
|
|
||||||
description: 'The version of the Nym Wallet to release'
|
|
||||||
default: '1.0.x'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
jobs:
|
|
||||||
create-release:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [ubuntu-latest]
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Create release
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
with:
|
|
||||||
body: >-
|
|
||||||
This is a pre-release
|
|
||||||
|
|
||||||
Download the wallet for your platform:
|
|
||||||
|
|
||||||
- [Linux](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_amd64_ubuntu20.04.AppImage)
|
|
||||||
- [MacOS](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_macos_11.dmg)
|
|
||||||
- [Windows](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_windows.msi)
|
|
||||||
prerelease: true
|
|
||||||
name: Nym Wallet v${{ inputs.nym_wallet_version}}
|
|
||||||
tag_name: nym-wallet-v${{ inputs.nym_wallet_version}}
|
|
||||||
@@ -13,9 +13,9 @@ jobs:
|
|||||||
- name: Install rsync
|
- name: Install rsync
|
||||||
run: sudo apt-get install rsync
|
run: sudo apt-get install rsync
|
||||||
- uses: rlespinasse/github-slug-action@v3.x
|
- uses: rlespinasse/github-slug-action@v3.x
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: '16'
|
||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
- name: Build dependencies
|
- name: Build dependencies
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ jobs:
|
|||||||
toolchain: stable
|
toolchain: stable
|
||||||
|
|
||||||
- name: Node v16
|
- name: Node v16
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16.x
|
||||||
|
|
||||||
- name: Install yarn for building application
|
- name: Install yarn for building application
|
||||||
run: yarn install
|
run: yarn install
|
||||||
|
|||||||
+208
-65
@@ -2,109 +2,83 @@
|
|||||||
|
|
||||||
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
|
## [Unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- nym-cli: added CLI tool for interacting with the Nyx blockchain and Nym mixnet smart contracts ([#1577])
|
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added.
|
||||||
- validator-client: added `query_contract_smart` and `query_contract_raw` on `NymdClient` ([#1558])
|
|
||||||
|
|
||||||
### 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])
|
|
||||||
|
|
||||||
[#1541]: https://github.com/nymtech/nym/pull/1541
|
|
||||||
[#1558]: https://github.com/nymtech/nym/pull/1558
|
|
||||||
[#1577]: https://github.com/nymtech/nym/pull/1577
|
|
||||||
[#1591]: https://github.com/nymtech/nym/pull/1591
|
|
||||||
|
|
||||||
|
|
||||||
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
|
|
||||||
- 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
|
|
||||||
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
|
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
|
||||||
|
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||||
|
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||||
|
- mixnet-contrat: Added staking_supply field to ContractStateParams.
|
||||||
- network-explorer-ui: Upgrade to React Router 6
|
- network-explorer-ui: Upgrade to React Router 6
|
||||||
- rewarding: replace circulating supply with staking supply in reward calculations ([#1324])
|
- rewarding: replace circulating supply with staking supply in reward calculations ([#1324])
|
||||||
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
|
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
|
||||||
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation
|
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation.
|
||||||
- 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])
|
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||||
- 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])
|
||||||
- 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-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
|
||||||
|
|
||||||
|
- 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])
|
||||||
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260])
|
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260])
|
||||||
- mixnode: the mixnode learned how to shutdown gracefully
|
- mixnode: the mixnode learned how to shutdown gracefully.
|
||||||
- mixnode: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service.
|
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
|
||||||
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
|
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
|
||||||
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
|
||||||
- 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
|
||||||
|
|
||||||
- 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`.
|
|
||||||
- network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328])
|
- network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328])
|
||||||
- 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`.
|
|
||||||
- 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
|
||||||
|
[#1257]: https://github.com/nymtech/nym/pull/1257
|
||||||
|
[#1258]: https://github.com/nymtech/nym/pull/1258
|
||||||
[#1260]: https://github.com/nymtech/nym/pull/1260
|
[#1260]: https://github.com/nymtech/nym/pull/1260
|
||||||
[#1261]: https://github.com/nymtech/nym/pull/1261
|
[#1261]: https://github.com/nymtech/nym/pull/1261
|
||||||
|
[#1265]: https://github.com/nymtech/nym/pull/1265
|
||||||
[#1267]: https://github.com/nymtech/nym/pull/1267
|
[#1267]: https://github.com/nymtech/nym/pull/1267
|
||||||
|
[#1275]: https://github.com/nymtech/nym/pull/1275
|
||||||
[#1278]: https://github.com/nymtech/nym/pull/1278
|
[#1278]: https://github.com/nymtech/nym/pull/1278
|
||||||
|
[#1284]: https://github.com/nymtech/nym/pull/1284
|
||||||
|
[#1292]: https://github.com/nymtech/nym/pull/1292
|
||||||
[#1295]: https://github.com/nymtech/nym/pull/1295
|
[#1295]: https://github.com/nymtech/nym/pull/1295
|
||||||
[#1302]: https://github.com/nymtech/nym/pull/1302
|
[#1302]: https://github.com/nymtech/nym/pull/1302
|
||||||
[#1308]: https://github.com/nymtech/nym/pull/1308
|
|
||||||
[#1318]: https://github.com/nymtech/nym/pull/1318
|
[#1318]: https://github.com/nymtech/nym/pull/1318
|
||||||
[#1322]: https://github.com/nymtech/nym/pull/1322
|
[#1322]: https://github.com/nymtech/nym/pull/1322
|
||||||
[#1324]: https://github.com/nymtech/nym/pull/1324
|
[#1324]: https://github.com/nymtech/nym/pull/1324
|
||||||
[#1328]: https://github.com/nymtech/nym/pull/1328
|
[#1328]: https://github.com/nymtech/nym/pull/1328
|
||||||
[#1329]: https://github.com/nymtech/nym/pull/1329
|
[#1329]: https://github.com/nymtech/nym/pull/1329
|
||||||
[#1353]: https://github.com/nymtech/nym/pull/1353
|
|
||||||
[#1376]: https://github.com/nymtech/nym/pull/1376
|
## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14)
|
||||||
[#1393]: https://github.com/nymtech/nym/pull/1393
|
|
||||||
[#1404]: https://github.com/nymtech/nym/pull/1404
|
- wallet: add simple CLI tool for decrypting and recovering the wallet file.
|
||||||
[#1419]: https://github.com/nymtech/nym/pull/1419
|
- wallet: added support for multiple accounts ([#1265])
|
||||||
[#1457]: https://github.com/nymtech/nym/pull/1457
|
- wallet: compound and claim reward endpoints for operators and delegators ([#1302])
|
||||||
[#1463]: https://github.com/nymtech/nym/pull/1463
|
- wallet: require password to switch accounts
|
||||||
[#1478]: https://github.com/nymtech/nym/pull/1478
|
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
|
||||||
[#1482]: https://github.com/nymtech/nym/pull/1482
|
- wallet: new delegation and rewards UI
|
||||||
[#1487]: https://github.com/nymtech/nym/pull/1487
|
- wallet: show version in nav bar
|
||||||
[#1496]: https://github.com/nymtech/nym/pull/1496
|
- wallet: contract admin route put back
|
||||||
[#1503]: https://github.com/nymtech/nym/pull/1503
|
- wallet: staking_supply field to StateParams
|
||||||
[#1520]: https://github.com/nymtech/nym/pull/1520
|
- wallet: show transaction hash for redeeming or compounding rewards
|
||||||
[#1573]: https://github.com/nymtech/nym/pull/1573
|
|
||||||
[#1576]: https://github.com/nymtech/nym/pull/1576
|
## [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)
|
||||||
|
|
||||||
@@ -137,10 +111,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)
|
||||||
@@ -219,6 +260,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
+866
-1267
File diff suppressed because it is too large
Load Diff
+8
-12
@@ -22,24 +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/mixnode-common",
|
"common/mixnode-common",
|
||||||
"common/network-defaults",
|
"common/network-defaults",
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
@@ -55,9 +53,9 @@ 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",
|
||||||
@@ -70,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"
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -79,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", "tokenomics-py", "clients/webassembly", "nym-wallet", "nym-connect"]
|
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly", "nym-wallet"]
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
test: clippy-all cargo-test wasm fmt
|
test: build clippy-all cargo-test wasm fmt
|
||||||
test-all: test cargo-test-expensive
|
|
||||||
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-all-main 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
|
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
|
|
||||||
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
|
||||||
|
|
||||||
@@ -36,27 +34,15 @@ clippy-all-connect:
|
|||||||
test-main:
|
test-main:
|
||||||
cargo test --all-features --workspace
|
cargo test --all-features --workspace
|
||||||
|
|
||||||
test-main-expensive:
|
|
||||||
cargo test --all-features --workspace -- --ignored
|
|
||||||
|
|
||||||
test-contracts:
|
test-contracts:
|
||||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||||
|
|
||||||
test-contracts-expensive:
|
|
||||||
cargo test --manifest-path contracts/Cargo.toml --all-features -- --ignored
|
|
||||||
|
|
||||||
test-wallet:
|
test-wallet:
|
||||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
||||||
|
|
||||||
test-wallet-expensive:
|
|
||||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
|
|
||||||
|
|
||||||
test-connect:
|
test-connect:
|
||||||
cargo test --manifest-path nym-connect/Cargo.toml --all-features
|
cargo test --manifest-path nym-connect/Cargo.toml --all-features
|
||||||
|
|
||||||
test-connect-expensive:
|
|
||||||
cargo test --manifest-path nym-connect/Cargo.toml --all-features -- --ignored
|
|
||||||
|
|
||||||
build-main:
|
build-main:
|
||||||
cargo build --workspace
|
cargo build --workspace
|
||||||
|
|
||||||
@@ -69,9 +55,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
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
|||||||
|
|
||||||
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
||||||
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
||||||
* nym-socks5-client - a Socks5 proxy you can run on your machine and use with existing applications.
|
* nym-socks5-client - a Socks5 proxy you can run on your machine, and use with existing applications
|
||||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
|
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
|
||||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "4.0"
|
dirs = "3.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
humantime-serde = "1.0"
|
humantime-serde = "1.0"
|
||||||
log = "0.4"
|
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,13 +25,11 @@ 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"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
coconut = ["gateway-client/coconut", "gateway-requests/coconut"]
|
coconut = ["gateway-client/coconut", "gateway-requests/coconut"]
|
||||||
@@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,7 +10,6 @@ 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_bonds, NymTopology};
|
use topology::{nym_topology_from_bonds, NymTopology};
|
||||||
@@ -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;
|
||||||
@@ -113,8 +114,12 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.disabled_credentials_mode = disabled_credentials_mode;
|
self.client.disabled_credentials_mode = disabled_credentials_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_gateway_endpoint(&mut self, gateway_endpoint: GatewayEndpoint) {
|
pub fn with_gateway_endpoint<S: Into<String>>(&mut self, id: S, owner: S, listener: S) {
|
||||||
self.client.gateway_endpoint = gateway_endpoint;
|
self.client.gateway_endpoint = GatewayEndpoint {
|
||||||
|
gateway_id: id.into(),
|
||||||
|
gateway_owner: owner.into(),
|
||||||
|
gateway_listener: listener.into(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||||
@@ -137,7 +142,7 @@ impl<T: NymConfig> Config<T> {
|
|||||||
|
|
||||||
pub fn set_high_default_traffic_volume(&mut self) {
|
pub fn set_high_default_traffic_volume(&mut self) {
|
||||||
self.debug.average_packet_delay = Duration::from_millis(10);
|
self.debug.average_packet_delay = Duration::from_millis(10);
|
||||||
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2_000_000); // basically don't really send cover messages
|
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2000000); // basically don't really send cover messages
|
||||||
self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s
|
self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,10 +206,6 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.gateway_endpoint.gateway_listener.clone()
|
self.client.gateway_endpoint.gateway_listener.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gateway_endpoint(&self) -> &GatewayEndpoint {
|
|
||||||
&self.client.gateway_endpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_database_path(&self) -> PathBuf {
|
pub fn get_database_path(&self) -> PathBuf {
|
||||||
self.client.database_path.clone()
|
self.client.database_path.clone()
|
||||||
}
|
}
|
||||||
@@ -271,31 +272,20 @@ impl<T: NymConfig> Default for Config<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct GatewayEndpoint {
|
struct GatewayEndpoint {
|
||||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||||
pub gateway_id: String,
|
gateway_id: String,
|
||||||
|
|
||||||
/// Address of the gateway owner to which the client should send messages.
|
/// Address of the gateway owner to which the client should send messages.
|
||||||
pub gateway_owner: String,
|
gateway_owner: String,
|
||||||
|
|
||||||
/// Address of the gateway listener to which all client requests should be sent.
|
/// Address of the gateway listener to which all client requests should be sent.
|
||||||
pub gateway_listener: String,
|
gateway_listener: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<topology::gateway::Node> for GatewayEndpoint {
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
fn from(node: topology::gateway::Node) -> GatewayEndpoint {
|
|
||||||
let gateway_listener = node.clients_address();
|
|
||||||
GatewayEndpoint {
|
|
||||||
gateway_id: node.identity_key.to_base58_string(),
|
|
||||||
gateway_owner: node.owner,
|
|
||||||
gateway_listener,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
|
||||||
pub struct Client<T> {
|
pub struct Client<T> {
|
||||||
/// Version of the client for which this configuration was created.
|
/// Version of the client for which this configuration was created.
|
||||||
#[serde(default = "missing_string_value")]
|
#[serde(default = "missing_string_value")]
|
||||||
@@ -365,7 +355,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(),
|
||||||
@@ -418,7 +408,7 @@ impl<T: NymConfig> Client<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Logging {}
|
pub struct Logging {}
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
//! Collection of initialization steps used by client implementations
|
|
||||||
|
|
||||||
use std::{sync::Arc, time::Duration};
|
|
||||||
|
|
||||||
use config::NymConfig;
|
|
||||||
use crypto::asymmetric::{encryption, identity};
|
|
||||||
use gateway_client::GatewayClient;
|
|
||||||
use gateway_requests::registration::handshake::SharedKeys;
|
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
|
||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use rand::seq::SliceRandom;
|
|
||||||
use rand::thread_rng;
|
|
||||||
use tap::TapFallible;
|
|
||||||
use topology::{filter::VersionFilterable, gateway};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
client::key_manager::KeyManager,
|
|
||||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
|
||||||
error::ClientCoreError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub async fn query_gateway_details(
|
|
||||||
validator_servers: Vec<Url>,
|
|
||||||
chosen_gateway_id: Option<&str>,
|
|
||||||
) -> Result<gateway::Node, ClientCoreError> {
|
|
||||||
let validator_api = validator_servers
|
|
||||||
.choose(&mut thread_rng())
|
|
||||||
.ok_or(ClientCoreError::ListOfValidatorApisIsEmpty)?;
|
|
||||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
|
||||||
|
|
||||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
|
||||||
let gateways = validator_client.get_cached_gateways().await?;
|
|
||||||
let valid_gateways = gateways
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|gateway| gateway.try_into().ok())
|
|
||||||
.collect::<Vec<gateway::Node>>();
|
|
||||||
|
|
||||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
|
||||||
|
|
||||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
|
||||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
|
||||||
// be working correctly)
|
|
||||||
if let Some(gateway_id) = chosen_gateway_id {
|
|
||||||
filtered_gateways
|
|
||||||
.iter()
|
|
||||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
|
||||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_id.to_string()))
|
|
||||||
.cloned()
|
|
||||||
} else {
|
|
||||||
filtered_gateways
|
|
||||||
.choose(&mut rand::thread_rng())
|
|
||||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
|
||||||
.cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn register_with_gateway_and_store_keys<T>(
|
|
||||||
gateway_details: gateway::Node,
|
|
||||||
config: &Config<T>,
|
|
||||||
) -> Result<(), ClientCoreError>
|
|
||||||
where
|
|
||||||
T: NymConfig,
|
|
||||||
{
|
|
||||||
let mut rng = OsRng;
|
|
||||||
let mut key_manager = KeyManager::new(&mut rng);
|
|
||||||
|
|
||||||
let shared_keys =
|
|
||||||
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await?;
|
|
||||||
key_manager.insert_gateway_shared_key(shared_keys);
|
|
||||||
|
|
||||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
|
||||||
Ok(key_manager
|
|
||||||
.store_keys(&pathfinder)
|
|
||||||
.tap_err(|err| log::error!("Failed to generate keys: {err}"))?)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn register_with_gateway(
|
|
||||||
gateway: &gateway::Node,
|
|
||||||
our_identity: Arc<identity::KeyPair>,
|
|
||||||
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
|
||||||
let timeout = Duration::from_millis(1500);
|
|
||||||
let mut gateway_client = GatewayClient::new_init(
|
|
||||||
gateway.clients_address(),
|
|
||||||
gateway.identity_key,
|
|
||||||
gateway.owner.clone(),
|
|
||||||
our_identity.clone(),
|
|
||||||
timeout,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
gateway_client
|
|
||||||
.establish_connection()
|
|
||||||
.await
|
|
||||||
.tap_err(|_| log::warn!("Failed to establish connection with gateway!"))?;
|
|
||||||
let shared_keys = gateway_client
|
|
||||||
.perform_initial_authentication()
|
|
||||||
.await
|
|
||||||
.tap_err(|_| log::warn!("Failed to register with the gateway!"))?;
|
|
||||||
Ok(shared_keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_address<T>(config: &Config<T>) -> Result<(), ClientCoreError>
|
|
||||||
where
|
|
||||||
T: config::NymConfig,
|
|
||||||
{
|
|
||||||
fn load_identity_keys(
|
|
||||||
pathfinder: &ClientKeyPathfinder,
|
|
||||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
|
||||||
let identity_keypair: identity::KeyPair =
|
|
||||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
|
||||||
pathfinder.private_identity_key().to_owned(),
|
|
||||||
pathfinder.public_identity_key().to_owned(),
|
|
||||||
))
|
|
||||||
.tap_err(|_| log::error!("Failed to read stored identity key files"))?;
|
|
||||||
Ok(identity_keypair)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_sphinx_keys(
|
|
||||||
pathfinder: &ClientKeyPathfinder,
|
|
||||||
) -> Result<encryption::KeyPair, ClientCoreError> {
|
|
||||||
let sphinx_keypair: encryption::KeyPair =
|
|
||||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
|
||||||
pathfinder.private_encryption_key().to_owned(),
|
|
||||||
pathfinder.public_encryption_key().to_owned(),
|
|
||||||
))
|
|
||||||
.tap_err(|_| log::error!("Failed to read stored sphinx key files"))?;
|
|
||||||
Ok(sphinx_keypair)
|
|
||||||
}
|
|
||||||
|
|
||||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
|
||||||
let identity_keypair = load_identity_keys(&pathfinder)?;
|
|
||||||
let sphinx_keypair = load_sphinx_keys(&pathfinder)?;
|
|
||||||
|
|
||||||
let client_recipient = Recipient::new(
|
|
||||||
*identity_keypair.public_key(),
|
|
||||||
*sphinx_keypair.public_key(),
|
|
||||||
// TODO: below only works under assumption that gateway address == gateway id
|
|
||||||
// (which currently is true)
|
|
||||||
NodeIdentity::from_base58_string(config.get_gateway_id())?,
|
|
||||||
);
|
|
||||||
|
|
||||||
println!("\nThe address of this client is: {}", client_recipient);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,2 @@
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
|
||||||
pub mod init;
|
|
||||||
|
|||||||
@@ -18,7 +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" }
|
|
||||||
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"] }
|
||||||
@@ -27,4 +26,4 @@ pemstore = { path = "../../common/pemstore" }
|
|||||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
|
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
coconut = ["credentials/coconut"]
|
coconut = ["credentials/coconut"]
|
||||||
@@ -1,34 +1,30 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Result;
|
|
||||||
use bip39::Mnemonic;
|
use bip39::Mnemonic;
|
||||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_client::nymd;
|
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::{MNEMONIC, NYMD_URL};
|
||||||
|
|
||||||
|
use network_defaults::{DEFAULT_NETWORK, DENOM, VOUCHER_INFO};
|
||||||
use validator_client::nymd::traits::CoconutBandwidthSigningClient;
|
use validator_client::nymd::traits::CoconutBandwidthSigningClient;
|
||||||
use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
|
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(&network_details)
|
|
||||||
.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(DEFAULT_NETWORK, 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, DENOM.to_string());
|
||||||
Ok(self
|
Ok(self
|
||||||
.nymd_client
|
.nymd_client
|
||||||
.deposit(
|
.deposit(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use clap::{Args, Subcommand};
|
|||||||
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;
|
||||||
@@ -19,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 {
|
||||||
@@ -37,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,
|
||||||
@@ -55,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,
|
||||||
@@ -100,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))]
|
||||||
@@ -116,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,24 +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::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,
|
||||||
}
|
}
|
||||||
@@ -36,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,
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
[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"
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.56"
|
||||||
|
|
||||||
@@ -20,8 +19,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.8", features = ["cargo", "derive"] }
|
clap = "2.33.0" # for the command line arguments
|
||||||
dirs = "4.0"
|
dirs = "3.0" # for determining default store directories in config
|
||||||
|
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,20 +33,19 @@ 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" }
|
|
||||||
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"]
|
||||||
@@ -56,4 +55,4 @@ eth = []
|
|||||||
serde_json = "1.0" # for the "textsend" example
|
serde_json = "1.0" # for the "textsend" example
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
||||||
@@ -11,7 +11,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
mod template;
|
mod template;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub enum SocketType {
|
pub enum SocketType {
|
||||||
WebSocket,
|
WebSocket,
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
@@ -109,7 +105,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
socket_type: SocketType,
|
socket_type: SocketType,
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -205,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
|
||||||
@@ -221,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(),
|
||||||
@@ -247,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)
|
||||||
@@ -258,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(
|
||||||
@@ -322,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
|
||||||
@@ -371,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 => {
|
||||||
@@ -432,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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+219
-165
@@ -1,138 +1,248 @@
|
|||||||
// 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 clap::Args;
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client_core::{config::GatewayEndpoint, error::ClientCoreError};
|
use client_core::client::key_manager::KeyManager;
|
||||||
|
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
use crypto::asymmetric::{encryption, identity};
|
||||||
|
use gateway_client::GatewayClient;
|
||||||
|
use gateway_requests::registration::handshake::SharedKeys;
|
||||||
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::thread_rng;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::client::config::Config;
|
||||||
client::config::Config,
|
use crate::commands::override_config;
|
||||||
commands::{override_config, OverrideConfig},
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use crate::commands::{
|
||||||
|
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ENABLED_CREDENTIALS_MODE_ARG_NAME,
|
||||||
|
ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
|
let app = App::new("init")
|
||||||
|
.about("Initialise a Nym client. Do this first!")
|
||||||
|
.arg(Arg::with_name("id")
|
||||||
|
.long("id")
|
||||||
|
.help("Id of the nym-mixnet-client we want to create config for.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("gateway")
|
||||||
|
.long("gateway")
|
||||||
|
.help("Id of the gateway we are going to connect to.")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("validators")
|
||||||
|
.long("validators")
|
||||||
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("disable-socket")
|
||||||
|
.long("disable-socket")
|
||||||
|
.help("Whether to not start the websocket")
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("port")
|
||||||
|
.short("p")
|
||||||
|
.long("port")
|
||||||
|
.help("Port for the socket (if applicable) to listen on in all subsequent runs")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("fastmode")
|
||||||
|
.long("fastmode")
|
||||||
|
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
||||||
|
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
||||||
|
);
|
||||||
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.help("Set this client to work in a disabled credentials mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||||
|
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.long(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.help("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 --testnet-mode instead")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||||
|
.required(true))
|
||||||
|
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||||
|
.required(true)
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
app
|
||||||
pub(crate) struct Init {
|
|
||||||
/// Id of the nym-mixnet-client we want to create config for.
|
|
||||||
#[clap(long)]
|
|
||||||
id: String,
|
|
||||||
|
|
||||||
/// Id of the gateway we are going to connect to.
|
|
||||||
#[clap(long)]
|
|
||||||
gateway: Option<String>,
|
|
||||||
|
|
||||||
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
|
||||||
/// potentially causing loss of access.
|
|
||||||
#[clap(long)]
|
|
||||||
force_register_gateway: bool,
|
|
||||||
|
|
||||||
/// Comma separated list of rest endpoints of the validators
|
|
||||||
#[clap(long)]
|
|
||||||
validators: Option<String>,
|
|
||||||
|
|
||||||
/// Whether to not start the websocket
|
|
||||||
#[clap(long)]
|
|
||||||
disable_socket: bool,
|
|
||||||
|
|
||||||
/// Port for the socket (if applicable) to listen on in all subsequent runs
|
|
||||||
#[clap(short, long)]
|
|
||||||
port: Option<u16>,
|
|
||||||
|
|
||||||
/// Mostly debug-related option to increase default traffic rate so that you would not need to
|
|
||||||
/// modify config post init
|
|
||||||
#[clap(long, hidden = true)]
|
|
||||||
fastmode: bool,
|
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
|
||||||
/// with bandwidth credential requirement.
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
#[clap(long)]
|
|
||||||
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 {
|
async fn register_with_gateway(
|
||||||
fn from(init_config: Init) -> Self {
|
gateway: &gateway::Node,
|
||||||
OverrideConfig {
|
our_identity: Arc<identity::KeyPair>,
|
||||||
validators: init_config.validators,
|
) -> Arc<SharedKeys> {
|
||||||
disable_socket: init_config.disable_socket,
|
let timeout = Duration::from_millis(1500);
|
||||||
port: init_config.port,
|
let mut gateway_client = GatewayClient::new_init(
|
||||||
fastmode: init_config.fastmode,
|
gateway.clients_address(),
|
||||||
|
gateway.identity_key,
|
||||||
|
gateway.owner.clone(),
|
||||||
|
our_identity.clone(),
|
||||||
|
timeout,
|
||||||
|
);
|
||||||
|
gateway_client
|
||||||
|
.establish_connection()
|
||||||
|
.await
|
||||||
|
.expect("failed to establish connection with the gateway!");
|
||||||
|
gateway_client
|
||||||
|
.perform_initial_authentication()
|
||||||
|
.await
|
||||||
|
.expect("failed to register with the gateway!")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
async fn gateway_details(
|
||||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
validator_servers: Vec<Url>,
|
||||||
|
chosen_gateway_id: Option<&str>,
|
||||||
|
) -> gateway::Node {
|
||||||
|
let validator_api = validator_servers
|
||||||
|
.choose(&mut thread_rng())
|
||||||
|
.expect("The list of validator apis is empty");
|
||||||
|
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||||
eth_private_key: Some(init_config.eth_private_key),
|
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||||
|
let valid_gateways = gateways
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
|
.collect::<Vec<gateway::Node>>();
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||||
eth_endpoint: Some(init_config.eth_endpoint),
|
|
||||||
}
|
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||||
|
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||||
|
// be working correctly)
|
||||||
|
if let Some(gateway_id) = chosen_gateway_id {
|
||||||
|
filtered_gateways
|
||||||
|
.iter()
|
||||||
|
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||||
|
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||||
|
.clone()
|
||||||
|
} else {
|
||||||
|
filtered_gateways
|
||||||
|
.choose(&mut rand::thread_rng())
|
||||||
|
.expect("there are no gateways on the network!")
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Init) {
|
fn show_address(config: &Config) {
|
||||||
|
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||||
|
let identity_keypair: identity::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_identity_key().to_owned(),
|
||||||
|
pathfinder.public_identity_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored identity key files");
|
||||||
|
identity_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||||
|
let sphinx_keypair: encryption::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_encryption_key().to_owned(),
|
||||||
|
pathfinder.public_encryption_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored sphinx key files");
|
||||||
|
sphinx_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||||
|
let identity_keypair = load_identity_keys(&pathfinder);
|
||||||
|
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||||
|
|
||||||
|
let client_recipient = Recipient::new(
|
||||||
|
*identity_keypair.public_key(),
|
||||||
|
*sphinx_keypair.public_key(),
|
||||||
|
// TODO: below only works under assumption that gateway address == gateway id
|
||||||
|
// (which currently is true)
|
||||||
|
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nThe address of this client is: {}", client_recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute(matches: ArgMatches<'static>) {
|
||||||
println!("Initialising client...");
|
println!("Initialising client...");
|
||||||
|
|
||||||
let id = &args.id;
|
let id = matches.value_of("id").unwrap(); // required for now
|
||||||
|
|
||||||
let already_init = Config::default_config_file_path(Some(id)).exists();
|
let already_init = if Config::default_config_file_path(Some(id)).exists() {
|
||||||
if already_init {
|
if matches.is_present("gateway") {
|
||||||
println!(
|
panic!("At the moment, gateway information can't be overwritten. If you want to point to a different gateway, client {}'s directory will need to be manually removed", id);
|
||||||
"Client \"{}\" was already initialised before! \
|
}
|
||||||
Config information will be overwritten (but keys will be kept)!",
|
println!("Client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
||||||
id
|
true
|
||||||
);
|
} else {
|
||||||
}
|
false
|
||||||
|
};
|
||||||
// Usually you only register with the gateway on the first init, however you can force
|
|
||||||
// re-registering if wanted.
|
|
||||||
let user_wants_force_register = args.force_register_gateway;
|
|
||||||
|
|
||||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
|
||||||
// the gateway (because this would create a new shared key).
|
|
||||||
// Unless the user really wants to.
|
|
||||||
let register_gateway = !already_init || user_wants_force_register;
|
|
||||||
|
|
||||||
// Attempt to use a user-provided gateway, if possible
|
|
||||||
let user_chosen_gateway_id = args.gateway.as_deref();
|
|
||||||
|
|
||||||
let mut config = Config::new(id);
|
let mut config = Config::new(id);
|
||||||
let override_config_fields = OverrideConfig::from(args.clone());
|
|
||||||
config = override_config(config, override_config_fields);
|
|
||||||
|
|
||||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config)
|
let mut rng = OsRng;
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| {
|
// TODO: ideally that should be the last thing that's being done to config.
|
||||||
eprintln!("Failed to setup gateway\nError: {err}");
|
// However, we are later further overriding it with gateway id
|
||||||
std::process::exit(1)
|
config = override_config(config, &matches);
|
||||||
});
|
if matches.is_present("fastmode") {
|
||||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
config.get_base_mut().set_high_default_traffic_volume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if client was already initialised, don't generate new keys, not re-register with gateway
|
||||||
|
// (because this would create new shared key)
|
||||||
|
if !already_init {
|
||||||
|
// create identity, encryption and ack keys.
|
||||||
|
let mut key_manager = KeyManager::new(&mut rng);
|
||||||
|
|
||||||
|
let chosen_gateway_id = matches.value_of("gateway");
|
||||||
|
log::trace!("Chosen gateway: {:?}", chosen_gateway_id);
|
||||||
|
|
||||||
|
let gateway_details = gateway_details(
|
||||||
|
config.get_base().get_validator_api_endpoints(),
|
||||||
|
chosen_gateway_id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
log::trace!("Used gateway: {}", gateway_details);
|
||||||
|
let shared_keys =
|
||||||
|
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||||
|
|
||||||
|
config.get_base_mut().with_gateway_endpoint(
|
||||||
|
gateway_details.identity_key.to_base58_string(),
|
||||||
|
gateway_details.owner.clone(),
|
||||||
|
gateway_details.clients_address(),
|
||||||
|
);
|
||||||
|
key_manager.insert_gateway_shared_key(shared_keys);
|
||||||
|
|
||||||
|
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||||
|
key_manager
|
||||||
|
.store_keys(&pathfinder)
|
||||||
|
.expect("Failed to generated keys");
|
||||||
|
println!("Saved all generated keys");
|
||||||
|
}
|
||||||
|
|
||||||
let config_save_location = config.get_config_file_save_location();
|
let config_save_location = config.get_config_file_save_location();
|
||||||
config
|
config
|
||||||
.save_to_file(None)
|
.save_to_file(None)
|
||||||
.expect("Failed to save the config file");
|
.expect("Failed to save the config file");
|
||||||
|
|
||||||
println!("Saved configuration file to {:?}", config_save_location);
|
println!("Saved configuration file to {:?}", config_save_location);
|
||||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||||
@@ -143,61 +253,5 @@ 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| {
|
show_address(&config);
|
||||||
eprintln!("Failed to show address\nError: {err}");
|
|
||||||
std::process::exit(1)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn setup_gateway(
|
|
||||||
id: &str,
|
|
||||||
register: bool,
|
|
||||||
user_chosen_gateway_id: Option<&str>,
|
|
||||||
config: &Config,
|
|
||||||
) -> Result<GatewayEndpoint, ClientCoreError> {
|
|
||||||
if register {
|
|
||||||
// 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.
|
|
||||||
println!("Configuring gateway");
|
|
||||||
let gateway = client_core::init::query_gateway_details(
|
|
||||||
config.get_base().get_validator_api_endpoints(),
|
|
||||||
user_chosen_gateway_id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
|
||||||
|
|
||||||
// Registering with gateway by setting up and writing shared keys to disk
|
|
||||||
log::trace!("Registering gateway");
|
|
||||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
|
||||||
.await?;
|
|
||||||
println!("Saved all generated keys");
|
|
||||||
|
|
||||||
Ok(gateway.into())
|
|
||||||
} else if user_chosen_gateway_id.is_some() {
|
|
||||||
// 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
|
|
||||||
// valid for the gateway being used
|
|
||||||
println!("Using gateway provided by user, keeping existing keys");
|
|
||||||
let gateway = client_core::init::query_gateway_details(
|
|
||||||
config.get_base().get_validator_api_endpoints(),
|
|
||||||
user_chosen_gateway_id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
|
||||||
Ok(gateway.into())
|
|
||||||
} else {
|
|
||||||
println!("Not registering gateway, will reuse existing config and keys");
|
|
||||||
let existing_config = Config::load_from_file(Some(id)).map_err(|err| {
|
|
||||||
log::error!(
|
|
||||||
"Unable to configure gateway: {err}. \n
|
|
||||||
Seems like the client was already initialized but it was not possible to read \
|
|
||||||
the existing configuration file. \n
|
|
||||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
|
||||||
removing the existing configuration and starting over."
|
|
||||||
);
|
|
||||||
ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(existing_config.get_base().get_gateway_endpoint().clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,14 @@
|
|||||||
// 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::{Parser, Subcommand};
|
use clap::ArgMatches;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub(crate) const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode";
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
||||||
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||||
@@ -15,148 +21,56 @@ pub(crate) mod init;
|
|||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
fn long_version() -> String {
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
format!(
|
raw.split(',')
|
||||||
r#"
|
.map(|raw_validator| {
|
||||||
{:<20}{}
|
raw_validator
|
||||||
{:<20}{}
|
.trim()
|
||||||
{:<20}{}
|
.parse()
|
||||||
{:<20}{}
|
.expect("one of the provided validator api urls is invalid")
|
||||||
{:<20}{}
|
})
|
||||||
{:<20}{}
|
.collect()
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
"#,
|
|
||||||
"Build Timestamp:",
|
|
||||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
|
||||||
"Build Version:",
|
|
||||||
env!("VERGEN_BUILD_SEMVER"),
|
|
||||||
"Commit SHA:",
|
|
||||||
env!("VERGEN_GIT_SHA"),
|
|
||||||
"Commit Date:",
|
|
||||||
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
|
||||||
"Commit Branch:",
|
|
||||||
env!("VERGEN_GIT_BRANCH"),
|
|
||||||
"rustc Version:",
|
|
||||||
env!("VERGEN_RUSTC_SEMVER"),
|
|
||||||
"rustc Channel:",
|
|
||||||
env!("VERGEN_RUSTC_CHANNEL"),
|
|
||||||
"cargo Profile:",
|
|
||||||
env!("VERGEN_CARGO_PROFILE"),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn long_version_static() -> &'static str {
|
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
||||||
Box::leak(long_version().into_boxed_str())
|
if let Some(raw_validators) = matches.value_of("validators") {
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
|
||||||
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)]
|
|
||||||
command: Commands,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
|
||||||
pub(crate) enum Commands {
|
|
||||||
/// Initialise a Nym client. Do this first!
|
|
||||||
Init(init::Init),
|
|
||||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
|
||||||
Run(run::Run),
|
|
||||||
/// Try to upgrade the client
|
|
||||||
Upgrade(upgrade::Upgrade),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuration that can be overridden.
|
|
||||||
pub(crate) struct OverrideConfig {
|
|
||||||
validators: Option<String>,
|
|
||||||
disable_socket: bool,
|
|
||||||
port: Option<u16>,
|
|
||||||
fastmode: bool,
|
|
||||||
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
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) {
|
|
||||||
match &args.command {
|
|
||||||
Commands::Init(m) => init::execute(m).await,
|
|
||||||
Commands::Run(m) => run::execute(m).await,
|
|
||||||
Commands::Upgrade(m) => upgrade::execute(m),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
|
||||||
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 matches.is_present("disable-socket") {
|
||||||
config = config.with_socket(SocketType::None);
|
config = config.with_socket(SocketType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(port) = args.port {
|
if let Some(port) = matches.value_of("port").map(str::parse) {
|
||||||
config = config.with_port(port);
|
if let Err(err) = port {
|
||||||
|
// if port was overridden, it must be parsable
|
||||||
|
panic!("Invalid port value provided - {:?}", err);
|
||||||
|
}
|
||||||
|
config = config.with_port(port.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
{
|
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
} else if !cfg!(feature = "eth") {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
|
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
|
} else if !cfg!(feature = "eth") {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
|
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||||
}
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
{
|
|
||||||
if args.enabled_credentials_mode {
|
|
||||||
config.get_base_mut().with_disabled_credentials(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
|
||||||
{
|
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 {
|
|
||||||
config.get_base_mut().set_high_default_traffic_volume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use clap::CommandFactory;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn verify_cli() {
|
|
||||||
Cli::command().debug_assert();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,76 +1,68 @@
|
|||||||
// 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::{
|
use crate::client::config::Config;
|
||||||
client::{config::Config, NymClient},
|
use crate::client::NymClient;
|
||||||
commands::{override_config, OverrideConfig},
|
use crate::commands::override_config;
|
||||||
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use crate::commands::{
|
||||||
|
ENABLED_CREDENTIALS_MODE_ARG_NAME, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||||
};
|
};
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
use clap::Args;
|
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use log::*;
|
use log::*;
|
||||||
use version_checker::is_minor_version_compatible;
|
use version_checker::is_minor_version_compatible;
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
pub(crate) struct Run {
|
let app = App::new("run")
|
||||||
/// Id of the nym-mixnet-client we want to run.
|
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
||||||
#[clap(long)]
|
.arg(Arg::with_name("id")
|
||||||
id: String,
|
.long("id")
|
||||||
|
.help("Id of the nym-mixnet-client we want to run.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
// the rest of arguments are optional, they are used to override settings in config file
|
||||||
|
.arg(Arg::with_name("validators")
|
||||||
|
.long("validators")
|
||||||
|
.help("Comma separated list rest rest endpoints of the validators")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("gateway")
|
||||||
|
.long("gateway")
|
||||||
|
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("disable-socket")
|
||||||
|
.long("disable-socket")
|
||||||
|
.help("Whether to not start the websocket")
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("port")
|
||||||
|
.short("p")
|
||||||
|
.long("port")
|
||||||
|
.help("Port for the socket (if applicable) to listen on")
|
||||||
|
.takes_value(true)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.help("Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||||
|
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.long(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.help("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 --testnet-mode instead")
|
||||||
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||||
|
.takes_value(true));
|
||||||
|
|
||||||
/// Comma separated list of rest endpoints of the validators
|
app
|
||||||
#[clap(long)]
|
|
||||||
validators: Option<String>,
|
|
||||||
|
|
||||||
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
|
|
||||||
/// ensure prior registration happened
|
|
||||||
#[clap(long)]
|
|
||||||
gateway: Option<String>,
|
|
||||||
|
|
||||||
/// Whether to not start the websocket
|
|
||||||
#[clap(long)]
|
|
||||||
disable_socket: bool,
|
|
||||||
|
|
||||||
/// Port for the socket to listen on
|
|
||||||
#[clap(short, long)]
|
|
||||||
port: Option<u16>,
|
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
|
||||||
/// with bandwidth credential requirement.
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
#[clap(long)]
|
|
||||||
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 {
|
|
||||||
fn from(run_config: Run) -> Self {
|
|
||||||
OverrideConfig {
|
|
||||||
validators: run_config.validators,
|
|
||||||
disable_socket: run_config.disable_socket,
|
|
||||||
port: run_config.port,
|
|
||||||
fastmode: false,
|
|
||||||
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this only checks compatibility between config the binary. It does not take into consideration
|
// this only checks compatibility between config the binary. It does not take into consideration
|
||||||
@@ -81,7 +73,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
|
||||||
@@ -92,8 +84,8 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Run) {
|
pub async fn execute(matches: ArgMatches<'static>) {
|
||||||
let id = &args.id;
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let mut config = match Config::load_from_file(Some(id)) {
|
let mut config = match Config::load_from_file(Some(id)) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
@@ -103,8 +95,7 @@ pub(crate) async fn execute(args: &Run) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let override_config_fields = OverrideConfig::from(args.clone());
|
config = override_config(config, &matches);
|
||||||
config = override_config(config, override_config_fields);
|
|
||||||
|
|
||||||
if !version_check(&config) {
|
if !version_check(&config) {
|
||||||
error!("failed the local version check");
|
error!("failed the local version check");
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
use config::defaults::default_api_endpoints;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use version_checker::Version;
|
|
||||||
|
|
||||||
use clap::Args;
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
use version_checker::Version;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||||
@@ -50,11 +49,14 @@ fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> !
|
|||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||||
pub(crate) struct Upgrade {
|
App::new("upgrade").about("Try to upgrade the client").arg(
|
||||||
/// Id of the nym-client we want to upgrade
|
Arg::with_name("id")
|
||||||
#[clap(long)]
|
.long("id")
|
||||||
id: String,
|
.help("Id of the nym-client we want to upgrade")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_config_version(config: &Config) -> Version {
|
fn parse_config_version(config: &Config) -> Version {
|
||||||
@@ -93,7 +95,7 @@ fn parse_package_version() -> Version {
|
|||||||
|
|
||||||
fn minor_0_12_upgrade(
|
fn minor_0_12_upgrade(
|
||||||
mut config: Config,
|
mut config: Config,
|
||||||
_matches: &Upgrade,
|
_matches: &ArgMatches<'_>,
|
||||||
config_version: &Version,
|
config_version: &Version,
|
||||||
package_version: &Version,
|
package_version: &Version,
|
||||||
) -> Config {
|
) -> Config {
|
||||||
@@ -105,6 +107,15 @@ fn minor_0_12_upgrade(
|
|||||||
|
|
||||||
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()
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
.set_custom_version(to_version.to_string().as_ref());
|
||||||
@@ -120,7 +131,7 @@ fn minor_0_12_upgrade(
|
|||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
|
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: &Version) {
|
||||||
loop {
|
loop {
|
||||||
let config_version = parse_config_version(&config);
|
let config_version = parse_config_version(&config);
|
||||||
|
|
||||||
@@ -132,7 +143,7 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
|
|||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 | 10 => outdated_upgrade(&config_version, package_version),
|
9 | 10 => outdated_upgrade(&config_version, package_version),
|
||||||
11 => minor_0_12_upgrade(config, args, &config_version, package_version),
|
11 => minor_0_12_upgrade(config, matches, &config_version, package_version),
|
||||||
_ => unsupported_upgrade(&config_version, package_version),
|
_ => unsupported_upgrade(&config_version, package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(&config_version, package_version),
|
_ => unsupported_upgrade(&config_version, package_version),
|
||||||
@@ -140,10 +151,10 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn execute(args: &Upgrade) {
|
pub fn execute(matches: &ArgMatches<'_>) {
|
||||||
let package_version = parse_package_version();
|
let package_version = parse_package_version();
|
||||||
|
|
||||||
let id = &args.id;
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||||
eprintln!("failed to load existing config file! - {:?}", err);
|
eprintln!("failed to load existing config file! - {:?}", err);
|
||||||
@@ -156,5 +167,5 @@ pub(crate) fn execute(args: &Upgrade) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||||
do_upgrade(existing_config, args, &package_version)
|
do_upgrade(existing_config, matches, &package_version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// 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 clap::{crate_version, Parser};
|
use clap::{crate_version, App, ArgMatches};
|
||||||
use network_defaults::setup_env;
|
use network_defaults::DEFAULT_NETWORK;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
@@ -10,12 +10,34 @@ 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 arg_matches = App::new("Nym Client")
|
||||||
setup_env(args.config_env_file.clone());
|
.version(crate_version!())
|
||||||
commands::execute(&args).await;
|
.long_version(&*long_version())
|
||||||
|
.author("Nymtech")
|
||||||
|
.about("Implementation of the Nym Client")
|
||||||
|
.subcommand(commands::init::command_args())
|
||||||
|
.subcommand(commands::run::command_args())
|
||||||
|
.subcommand(commands::upgrade::command_args())
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
execute(arg_matches).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(matches: ArgMatches<'static>) {
|
||||||
|
match matches.subcommand() {
|
||||||
|
("init", Some(m)) => commands::init::execute(m.clone()).await,
|
||||||
|
("run", Some(m)) => commands::run::execute(m.clone()).await,
|
||||||
|
("upgrade", Some(m)) => commands::upgrade::execute(m),
|
||||||
|
_ => println!("{}", usage()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage() -> &'static str {
|
||||||
|
"usage: --help to see available options.\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn banner() -> String {
|
fn banner() -> String {
|
||||||
@@ -35,6 +57,40 @@ fn banner() -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn long_version() -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
"#,
|
||||||
|
"Build Timestamp:",
|
||||||
|
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
|
"Build Version:",
|
||||||
|
env!("VERGEN_BUILD_SEMVER"),
|
||||||
|
"Commit SHA:",
|
||||||
|
env!("VERGEN_GIT_SHA"),
|
||||||
|
"Commit Date:",
|
||||||
|
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
||||||
|
"Commit Branch:",
|
||||||
|
env!("VERGEN_GIT_BRANCH"),
|
||||||
|
"rustc Version:",
|
||||||
|
env!("VERGEN_RUSTC_SEMVER"),
|
||||||
|
"rustc Channel:",
|
||||||
|
env!("VERGEN_RUSTC_CHANNEL"),
|
||||||
|
"cargo Profile:",
|
||||||
|
env!("VERGEN_CARGO_PROFILE"),
|
||||||
|
"Network:",
|
||||||
|
DEFAULT_NETWORK
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_logging() {
|
fn setup_logging() {
|
||||||
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
||||||
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ edition = "2021"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
nymsphinx = { path = "../../../common/nymsphinx" }
|
nymsphinx = { path = "../../../common/nymsphinx" }
|
||||||
@@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
// no need to go fancy here like we've done in other places.
|
// no need to go fancy here like we've done in other places.
|
||||||
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Serialize, Deserialize)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
pub kind: ErrorKind,
|
pub kind: ErrorKind,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
@@ -30,7 +30,7 @@ impl Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Serialize, Deserialize)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
/// The received request contained no data.
|
/// The received request contained no data.
|
||||||
EmptyRequest = 0x01,
|
EmptyRequest = 0x01,
|
||||||
|
|||||||
+10
-11
@@ -1,8 +1,7 @@
|
|||||||
[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"
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.56"
|
||||||
|
|
||||||
@@ -11,8 +10,9 @@ name = "nym_socks5"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.2.8", features = ["cargo", "derive"] }
|
clap = "2.33.0"
|
||||||
dirs = "4.0"
|
dirs = "3.0" # for determining default store directories in config
|
||||||
|
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,26 +26,25 @@ 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" }
|
|
||||||
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"]
|
||||||
eth = []
|
eth = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
@@ -93,7 +89,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Socks5 {
|
pub struct Socks5 {
|
||||||
/// The port on which the client will be listening for incoming requests
|
/// The port on which the client will be listening for incoming requests
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -206,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
|
||||||
@@ -222,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(),
|
||||||
@@ -248,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)
|
||||||
@@ -259,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];
|
||||||
@@ -281,57 +264,40 @@ 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() => match message {
|
||||||
log::debug!("Received message: {:?}", message);
|
Some(Socks5ControlMessage::Stop) => {
|
||||||
match message {
|
log::info!("Received: {:?}", message);
|
||||||
Some(Socks5ControlMessage::Stop) => {
|
log::info!("Shutting down");
|
||||||
log::info!("Received stop message");
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::info!("Channel closed, stopping");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None => log::info!("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
|
||||||
@@ -361,52 +327,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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+222
-172
@@ -1,202 +1,252 @@
|
|||||||
// 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 clap::Args;
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client_core::{config::GatewayEndpoint, error::ClientCoreError};
|
use client_core::client::key_manager::KeyManager;
|
||||||
|
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
use crypto::asymmetric::{encryption, identity};
|
||||||
|
use gateway_client::GatewayClient;
|
||||||
|
use gateway_requests::registration::handshake::SharedKeys;
|
||||||
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
|
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::client::config::Config;
|
||||||
client::config::Config,
|
use crate::commands::override_config;
|
||||||
commands::{override_config, OverrideConfig},
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use crate::commands::{
|
||||||
|
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ENABLED_CREDENTIALS_MODE_ARG_NAME,
|
||||||
|
ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
|
let app = App::new("init")
|
||||||
|
.about("Initialise a Nym client. Do this first!")
|
||||||
|
.arg(Arg::with_name("id")
|
||||||
|
.long("id")
|
||||||
|
.help("Id of the nym-mixnet-client we want to create config for.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("provider")
|
||||||
|
.long("provider")
|
||||||
|
.help("Address of the socks5 provider to send messages to.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("gateway")
|
||||||
|
.long("gateway")
|
||||||
|
.help("Id of the gateway we are going to connect to.")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("validators")
|
||||||
|
.long("validators")
|
||||||
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("port")
|
||||||
|
.short("p")
|
||||||
|
.long("port")
|
||||||
|
.help("Port for the socket to listen on in all subsequent runs")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("fastmode")
|
||||||
|
.long("fastmode")
|
||||||
|
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
||||||
|
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
||||||
|
);
|
||||||
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.help("Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||||
|
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.long(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.help("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 --testnet-mode instead")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
||||||
|
.required(true))
|
||||||
|
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
||||||
|
.required(true)
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
app
|
||||||
pub(crate) struct Init {
|
|
||||||
/// Id of the nym-mixnet-client we want to create config for.
|
|
||||||
#[clap(long)]
|
|
||||||
id: String,
|
|
||||||
|
|
||||||
/// Address of the socks5 provider to send messages to.
|
|
||||||
#[clap(long)]
|
|
||||||
provider: String,
|
|
||||||
|
|
||||||
/// Id of the gateway we are going to connect to.
|
|
||||||
#[clap(long)]
|
|
||||||
gateway: Option<String>,
|
|
||||||
|
|
||||||
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
|
||||||
/// potentially causing loss of access.
|
|
||||||
#[clap(long)]
|
|
||||||
force_register_gateway: bool,
|
|
||||||
|
|
||||||
/// Comma separated list of rest endpoints of the validators
|
|
||||||
#[clap(long)]
|
|
||||||
validators: Option<String>,
|
|
||||||
|
|
||||||
/// Port for the socket to listen on in all subsequent runs
|
|
||||||
#[clap(short, long)]
|
|
||||||
port: Option<u16>,
|
|
||||||
|
|
||||||
/// Mostly debug-related option to increase default traffic rate so that you would not need to
|
|
||||||
/// modify config post init
|
|
||||||
#[clap(long, hidden = true)]
|
|
||||||
fastmode: bool,
|
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
|
||||||
/// with bandwidth credential requirement.
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
#[clap(long)]
|
|
||||||
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 {
|
// TODO: make this private again after refactoring the config setup
|
||||||
fn from(init_config: Init) -> Self {
|
pub async fn register_with_gateway(
|
||||||
OverrideConfig {
|
gateway: &gateway::Node,
|
||||||
validators: init_config.validators,
|
our_identity: Arc<identity::KeyPair>,
|
||||||
port: init_config.port,
|
) -> Arc<SharedKeys> {
|
||||||
fastmode: init_config.fastmode,
|
let timeout = Duration::from_millis(1500);
|
||||||
|
let mut gateway_client = GatewayClient::new_init(
|
||||||
|
gateway.clients_address(),
|
||||||
|
gateway.identity_key,
|
||||||
|
gateway.owner.clone(),
|
||||||
|
our_identity.clone(),
|
||||||
|
timeout,
|
||||||
|
);
|
||||||
|
gateway_client
|
||||||
|
.establish_connection()
|
||||||
|
.await
|
||||||
|
.expect("failed to establish connection with the gateway!");
|
||||||
|
gateway_client
|
||||||
|
.perform_initial_authentication()
|
||||||
|
.await
|
||||||
|
.expect("failed to register with the gateway!")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
// TODO: make this private again after refactoring the config setup
|
||||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
pub async fn gateway_details(
|
||||||
|
validator_servers: Vec<Url>,
|
||||||
|
chosen_gateway_id: Option<&str>,
|
||||||
|
) -> gateway::Node {
|
||||||
|
let validator_api = validator_servers
|
||||||
|
.choose(&mut thread_rng())
|
||||||
|
.expect("The list of validator apis is empty");
|
||||||
|
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||||
eth_private_key: Some(init_config.eth_private_key),
|
let valid_gateways = gateways
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
|
.collect::<Vec<gateway::Node>>();
|
||||||
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||||
eth_endpoint: Some(init_config.eth_endpoint),
|
|
||||||
}
|
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||||
|
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||||
|
// be working correctly)
|
||||||
|
if let Some(gateway_id) = chosen_gateway_id {
|
||||||
|
filtered_gateways
|
||||||
|
.iter()
|
||||||
|
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||||
|
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||||
|
.clone()
|
||||||
|
} else {
|
||||||
|
filtered_gateways
|
||||||
|
.choose(&mut rand::thread_rng())
|
||||||
|
.expect("there are no gateways on the network!")
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Init) {
|
// TODO: make this private again after refactoring the config setup
|
||||||
|
pub fn show_address(config: &Config) {
|
||||||
|
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||||
|
let identity_keypair: identity::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_identity_key().to_owned(),
|
||||||
|
pathfinder.public_identity_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored identity key files");
|
||||||
|
identity_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||||
|
let sphinx_keypair: encryption::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_encryption_key().to_owned(),
|
||||||
|
pathfinder.public_encryption_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored sphinx key files");
|
||||||
|
sphinx_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||||
|
let identity_keypair = load_identity_keys(&pathfinder);
|
||||||
|
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||||
|
|
||||||
|
let client_recipient = Recipient::new(
|
||||||
|
*identity_keypair.public_key(),
|
||||||
|
*sphinx_keypair.public_key(),
|
||||||
|
// TODO: below only works under assumption that gateway address == gateway id
|
||||||
|
// (which currently is true)
|
||||||
|
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nThe address of this client is: {}", client_recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute(matches: ArgMatches<'static>) {
|
||||||
println!("Initialising client...");
|
println!("Initialising client...");
|
||||||
|
|
||||||
let id = &args.id;
|
let id = matches.value_of("id").unwrap(); // required for now
|
||||||
let provider_address = &args.provider;
|
let provider_address = matches.value_of("provider").unwrap();
|
||||||
|
|
||||||
let already_init = Config::default_config_file_path(Some(id)).exists();
|
let already_init = if Config::default_config_file_path(Some(id)).exists() {
|
||||||
if already_init {
|
if matches.is_present("gateway") {
|
||||||
println!(
|
panic!("At the moment, gateway information can't be overwritten. If you want to point to a different gateway, client {}'s directory will need to be manually removed", id);
|
||||||
"SOCKS5 client \"{}\" was already initialised before! \
|
}
|
||||||
Config information will be overwritten (but keys will be kept)!",
|
println!("Socks5 client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
||||||
id
|
true
|
||||||
);
|
} else {
|
||||||
}
|
false
|
||||||
|
};
|
||||||
// Usually you only register with the gateway on the first init, however you can force
|
|
||||||
// re-registering if wanted.
|
|
||||||
let user_wants_force_register = args.force_register_gateway;
|
|
||||||
|
|
||||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
|
||||||
// the gateway (because this would create a new shared key).
|
|
||||||
// Unless the user really wants to.
|
|
||||||
let register_gateway = !already_init || user_wants_force_register;
|
|
||||||
|
|
||||||
// Attempt to use a user-provided gateway, if possible
|
|
||||||
let user_chosen_gateway_id = args.gateway.as_deref();
|
|
||||||
|
|
||||||
let mut config = Config::new(id, provider_address);
|
let mut config = Config::new(id, provider_address);
|
||||||
let override_config_fields = OverrideConfig::from(args.clone());
|
|
||||||
config = override_config(config, override_config_fields);
|
|
||||||
|
|
||||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config)
|
let mut rng = OsRng;
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| {
|
// TODO: ideally that should be the last thing that's being done to config.
|
||||||
eprintln!("Failed to setup gateway\nError: {err}");
|
// However, we are later further overriding it with gateway id
|
||||||
std::process::exit(1)
|
config = override_config(config, &matches);
|
||||||
});
|
if matches.is_present("fastmode") {
|
||||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
config.get_base_mut().set_high_default_traffic_volume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if client was already initialised, don't generate new keys, not re-register with gateway
|
||||||
|
// (because this would create new shared key)
|
||||||
|
if !already_init {
|
||||||
|
// create identity, encryption and ack keys.
|
||||||
|
let mut key_manager = KeyManager::new(&mut rng);
|
||||||
|
|
||||||
|
let chosen_gateway_id = matches.value_of("gateway");
|
||||||
|
|
||||||
|
let gateway_details = gateway_details(
|
||||||
|
config.get_base().get_validator_api_endpoints(),
|
||||||
|
chosen_gateway_id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let shared_keys =
|
||||||
|
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||||
|
|
||||||
|
config.get_base_mut().with_gateway_endpoint(
|
||||||
|
gateway_details.identity_key.to_base58_string(),
|
||||||
|
gateway_details.owner.clone(),
|
||||||
|
gateway_details.clients_address(),
|
||||||
|
);
|
||||||
|
key_manager.insert_gateway_shared_key(shared_keys);
|
||||||
|
|
||||||
|
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||||
|
key_manager
|
||||||
|
.store_keys(&pathfinder)
|
||||||
|
.expect("Failed to generated keys");
|
||||||
|
println!("Saved all generated keys");
|
||||||
|
}
|
||||||
|
|
||||||
let config_save_location = config.get_config_file_save_location();
|
let config_save_location = config.get_config_file_save_location();
|
||||||
config
|
config
|
||||||
.save_to_file(None)
|
.save_to_file(None)
|
||||||
.expect("Failed to save the config file");
|
.expect("Failed to save the config file");
|
||||||
|
|
||||||
println!("Saved configuration file to {:?}", config_save_location);
|
println!("Saved configuration file to {:?}", config_save_location);
|
||||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
||||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
println!("Client configuration completed.\n\n\n");
|
||||||
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
|
|
||||||
log::debug!(
|
|
||||||
"Gateway listener: {}",
|
|
||||||
config.get_base().get_gateway_listener()
|
|
||||||
);
|
|
||||||
println!("Client configuration completed.");
|
|
||||||
|
|
||||||
client_core::init::show_address(config.get_base()).unwrap_or_else(|err| {
|
show_address(&config);
|
||||||
eprintln!("Failed to show address\nError: {err}");
|
|
||||||
std::process::exit(1)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn setup_gateway(
|
|
||||||
id: &str,
|
|
||||||
register: bool,
|
|
||||||
user_chosen_gateway_id: Option<&str>,
|
|
||||||
config: &Config,
|
|
||||||
) -> Result<GatewayEndpoint, ClientCoreError> {
|
|
||||||
if register {
|
|
||||||
// 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.
|
|
||||||
println!("Configuring gateway");
|
|
||||||
let gateway = client_core::init::query_gateway_details(
|
|
||||||
config.get_base().get_validator_api_endpoints(),
|
|
||||||
user_chosen_gateway_id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
|
||||||
|
|
||||||
// Registering with gateway by setting up and writing shared keys to disk
|
|
||||||
log::trace!("Registering gateway");
|
|
||||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
|
||||||
.await?;
|
|
||||||
println!("Saved all generated keys");
|
|
||||||
|
|
||||||
Ok(gateway.into())
|
|
||||||
} else if user_chosen_gateway_id.is_some() {
|
|
||||||
// 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
|
|
||||||
// valid for the gateway being used
|
|
||||||
println!("Using gateway provided by user, keeping existing keys");
|
|
||||||
let gateway = client_core::init::query_gateway_details(
|
|
||||||
config.get_base().get_validator_api_endpoints(),
|
|
||||||
user_chosen_gateway_id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
|
||||||
Ok(gateway.into())
|
|
||||||
} else {
|
|
||||||
println!("Not registering gateway, will reuse existing config and keys");
|
|
||||||
let existing_config = Config::load_from_file(Some(id)).map_err(|err| {
|
|
||||||
log::error!(
|
|
||||||
"Unable to configure gateway: {err}. \n
|
|
||||||
Seems like the client was already initialized but it was not possible to read \
|
|
||||||
the existing configuration file. \n
|
|
||||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
|
||||||
removing the existing configuration and starting over."
|
|
||||||
);
|
|
||||||
ClientCoreError::CouldNotLoadExistingGatewayConfiguration(err)
|
|
||||||
})?;
|
|
||||||
Ok(existing_config.get_base().get_gateway_endpoint().clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,18 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::ArgMatches;
|
||||||
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;
|
||||||
|
|
||||||
|
pub(crate) const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode";
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
||||||
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||||
@@ -16,141 +21,52 @@ pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
|||||||
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
|
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001";
|
"0000000000000000000000000000000000000000000000000000000000000001";
|
||||||
|
|
||||||
fn long_version() -> String {
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
format!(
|
raw.split(',')
|
||||||
r#"
|
.map(|raw_validator| {
|
||||||
{:<20}{}
|
raw_validator
|
||||||
{:<20}{}
|
.trim()
|
||||||
{:<20}{}
|
.parse()
|
||||||
{:<20}{}
|
.expect("one of the provided validator api urls is invalid")
|
||||||
{:<20}{}
|
})
|
||||||
{:<20}{}
|
.collect()
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
"#,
|
|
||||||
"Build Timestamp:",
|
|
||||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
|
||||||
"Build Version:",
|
|
||||||
env!("VERGEN_BUILD_SEMVER"),
|
|
||||||
"Commit SHA:",
|
|
||||||
env!("VERGEN_GIT_SHA"),
|
|
||||||
"Commit Date:",
|
|
||||||
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
|
||||||
"Commit Branch:",
|
|
||||||
env!("VERGEN_GIT_BRANCH"),
|
|
||||||
"rustc Version:",
|
|
||||||
env!("VERGEN_RUSTC_SEMVER"),
|
|
||||||
"rustc Channel:",
|
|
||||||
env!("VERGEN_RUSTC_CHANNEL"),
|
|
||||||
"cargo Profile:",
|
|
||||||
env!("VERGEN_CARGO_PROFILE"),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn long_version_static() -> &'static str {
|
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
||||||
Box::leak(long_version().into_boxed_str())
|
if let Some(raw_validators) = matches.value_of("validators") {
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
|
||||||
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)]
|
|
||||||
command: Commands,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
|
||||||
pub(crate) enum Commands {
|
|
||||||
/// Initialise a Nym client. Do this first!
|
|
||||||
Init(init::Init),
|
|
||||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
|
||||||
Run(run::Run),
|
|
||||||
/// Try to upgrade the client
|
|
||||||
Upgrade(upgrade::Upgrade),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuration that can be overridden.
|
|
||||||
pub(crate) struct OverrideConfig {
|
|
||||||
validators: Option<String>,
|
|
||||||
port: Option<u16>,
|
|
||||||
fastmode: bool,
|
|
||||||
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
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) {
|
|
||||||
match &args.command {
|
|
||||||
Commands::Init(m) => init::execute(m).await,
|
|
||||||
Commands::Run(m) => run::execute(m).await,
|
|
||||||
Commands::Upgrade(m) => upgrade::execute(m),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
|
||||||
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) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
||||||
config = config.with_port(port);
|
if let Err(err) = port {
|
||||||
}
|
// if port was overridden, it must be parsable
|
||||||
|
panic!("Invalid port value provided - {:?}", err);
|
||||||
#[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(any(feature = "eth", feature = "coconut"))]
|
|
||||||
{
|
|
||||||
if args.enabled_credentials_mode {
|
|
||||||
config.get_base_mut().with_disabled_credentials(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
config = config.with_port(port.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.fastmode {
|
#[cfg(not(feature = "coconut"))]
|
||||||
config.get_base_mut().set_high_default_traffic_volume();
|
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
} else if !cfg!(feature = "eth") {
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
|
} else if !cfg!(feature = "eth") {
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
|
||||||
|
config.get_base_mut().with_disabled_credentials(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use clap::CommandFactory;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn verify_cli() {
|
|
||||||
Cli::command().debug_assert();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,79 +1,74 @@
|
|||||||
// 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::{
|
use crate::client::config::Config;
|
||||||
client::{config::Config, NymClient},
|
use crate::client::NymClient;
|
||||||
commands::{override_config, OverrideConfig},
|
use crate::commands::override_config;
|
||||||
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use crate::commands::{
|
||||||
|
ENABLED_CREDENTIALS_MODE_ARG_NAME, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
||||||
};
|
};
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
use clap::Args;
|
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use log::*;
|
use log::*;
|
||||||
use version_checker::is_minor_version_compatible;
|
use version_checker::is_minor_version_compatible;
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
pub(crate) struct Run {
|
let app = App::new("run")
|
||||||
/// Id of the nym-mixnet-client we want to run.
|
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
||||||
#[clap(long)]
|
.arg(Arg::with_name("id")
|
||||||
id: String,
|
.long("id")
|
||||||
|
.help("Id of the nym-mixnet-client we want to run.")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
// the rest of arguments are optional, they are used to override settings in config file
|
||||||
|
.arg(Arg::with_name("config")
|
||||||
|
.long("config")
|
||||||
|
.help("Custom path to the nym-mixnet-client configuration file")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("provider")
|
||||||
|
.long("provider")
|
||||||
|
.help("Address of the socks5 provider to send messages to.")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("validators")
|
||||||
|
.long("validators")
|
||||||
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("gateway")
|
||||||
|
.long("gateway")
|
||||||
|
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name("port")
|
||||||
|
.short("p")
|
||||||
|
.long("port")
|
||||||
|
.help("Port for the socket to listen on")
|
||||||
|
.takes_value(true)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "eth")]
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
||||||
|
.help("Set this client to work in a disabled credentials mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
||||||
|
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
||||||
|
)
|
||||||
|
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.long(ETH_ENDPOINT_ARG_NAME)
|
||||||
|
.help("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 --testnet-mode instead")
|
||||||
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
||||||
|
.takes_value(true));
|
||||||
|
|
||||||
/// Custom path to the nym-mixnet-client configuration file
|
app
|
||||||
#[clap(long)]
|
|
||||||
config: Option<String>,
|
|
||||||
|
|
||||||
/// Address of the socks5 provider to send messages to.
|
|
||||||
#[clap(long)]
|
|
||||||
provider: Option<String>,
|
|
||||||
|
|
||||||
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
|
|
||||||
/// ensure prior registration happened
|
|
||||||
#[clap(long)]
|
|
||||||
gateway: Option<String>,
|
|
||||||
|
|
||||||
/// Comma separated list of rest endpoints of the validators
|
|
||||||
#[clap(long)]
|
|
||||||
validators: Option<String>,
|
|
||||||
|
|
||||||
/// Port for the socket to listen on
|
|
||||||
#[clap(short, long)]
|
|
||||||
port: Option<u16>,
|
|
||||||
|
|
||||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
|
||||||
/// with bandwidth credential requirement.
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
#[clap(long)]
|
|
||||||
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 {
|
|
||||||
fn from(run_config: Run) -> Self {
|
|
||||||
OverrideConfig {
|
|
||||||
validators: run_config.validators,
|
|
||||||
port: run_config.port,
|
|
||||||
fastmode: false,
|
|
||||||
|
|
||||||
#[cfg(any(feature = "eth", feature = "coconut"))]
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this only checks compatibility between config the binary. It does not take into consideration
|
// this only checks compatibility between config the binary. It does not take into consideration
|
||||||
@@ -81,13 +76,8 @@ impl From<Run> for OverrideConfig {
|
|||||||
fn version_check(cfg: &Config) -> bool {
|
fn version_check(cfg: &Config) -> bool {
|
||||||
let binary_version = env!("CARGO_PKG_VERSION");
|
let binary_version = env!("CARGO_PKG_VERSION");
|
||||||
let config_version = cfg.get_base().get_version();
|
let config_version = cfg.get_base().get_version();
|
||||||
if binary_version == config_version {
|
if binary_version != config_version {
|
||||||
true
|
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
||||||
} else {
|
|
||||||
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
|
||||||
@@ -95,11 +85,13 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Run) {
|
pub async fn execute(matches: ArgMatches<'static>) {
|
||||||
let id = &args.id;
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let mut config = match Config::load_from_file(Some(id)) {
|
let mut config = match Config::load_from_file(Some(id)) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
@@ -109,8 +101,7 @@ pub(crate) async fn execute(args: &Run) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let override_config_fields = OverrideConfig::from(args.clone());
|
config = override_config(config, &matches);
|
||||||
config = override_config(config, override_config_fields);
|
|
||||||
|
|
||||||
if !version_check(&config) {
|
if !version_check(&config) {
|
||||||
error!("failed the local version check");
|
error!("failed the local version check");
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
use config::defaults::default_api_endpoints;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::process;
|
||||||
use version_checker::Version;
|
use version_checker::Version;
|
||||||
|
|
||||||
use clap::Args;
|
|
||||||
use std::{fmt::Display, process};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||||
print_failed_upgrade(from_version, to_version);
|
print_failed_upgrade(from_version, to_version);
|
||||||
@@ -49,11 +49,14 @@ fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> !
|
|||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Clone)]
|
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||||
pub(crate) struct Upgrade {
|
App::new("upgrade").about("Try to upgrade the client").arg(
|
||||||
/// Id of the nym-client we want to upgrade
|
Arg::with_name("id")
|
||||||
#[clap(long)]
|
.long("id")
|
||||||
id: String,
|
.help("Id of the nym-client we want to upgrade")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_config_version(config: &Config) -> Version {
|
fn parse_config_version(config: &Config) -> Version {
|
||||||
@@ -92,7 +95,7 @@ fn parse_package_version() -> Version {
|
|||||||
|
|
||||||
fn minor_0_12_upgrade(
|
fn minor_0_12_upgrade(
|
||||||
mut config: Config,
|
mut config: Config,
|
||||||
_args: &Upgrade,
|
_matches: &ArgMatches<'_>,
|
||||||
config_version: &Version,
|
config_version: &Version,
|
||||||
package_version: &Version,
|
package_version: &Version,
|
||||||
) -> Config {
|
) -> Config {
|
||||||
@@ -104,6 +107,15 @@ fn minor_0_12_upgrade(
|
|||||||
|
|
||||||
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()
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
.set_custom_version(to_version.to_string().as_ref());
|
||||||
@@ -119,30 +131,30 @@ fn minor_0_12_upgrade(
|
|||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
|
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Version) {
|
||||||
loop {
|
loop {
|
||||||
let config_version = parse_config_version(&config);
|
let config_version = parse_config_version(&config);
|
||||||
|
|
||||||
if &config_version == package_version {
|
if config_version == package_version {
|
||||||
println!("You're using the most recent version!");
|
println!("You're using the most recent version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 | 10 => outdated_upgrade(&config_version, package_version),
|
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||||
11 => minor_0_12_upgrade(config, args, &config_version, package_version),
|
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||||
_ => unsupported_upgrade(&config_version, package_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(&config_version, package_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn execute(args: &Upgrade) {
|
pub fn execute(matches: &ArgMatches<'_>) {
|
||||||
let package_version = parse_package_version();
|
let package_version = parse_package_version();
|
||||||
|
|
||||||
let id = &args.id;
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||||
eprintln!("failed to load existing config file! - {:?}", err);
|
eprintln!("failed to load existing config file! - {:?}", err);
|
||||||
@@ -155,5 +167,5 @@ pub(crate) fn execute(args: &Upgrade) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||||
do_upgrade(existing_config, args, &package_version)
|
do_upgrade(existing_config, matches, package_version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// 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 clap::{crate_version, Parser};
|
use clap::{crate_version, App, ArgMatches};
|
||||||
use network_defaults::setup_env;
|
use network_defaults::DEFAULT_NETWORK;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
mod commands;
|
mod commands;
|
||||||
@@ -10,12 +10,34 @@ 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 arg_matches = App::new("Nym Socks5 Proxy")
|
||||||
setup_env(args.config_env_file.clone());
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
commands::execute(&args).await;
|
.author("Nymtech")
|
||||||
|
.long_version(&*long_version())
|
||||||
|
.about("A Socks5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address")
|
||||||
|
.subcommand(commands::init::command_args())
|
||||||
|
.subcommand(commands::run::command_args())
|
||||||
|
.subcommand(commands::upgrade::command_args())
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
execute(arg_matches).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(matches: ArgMatches<'static>) {
|
||||||
|
match matches.subcommand() {
|
||||||
|
("init", Some(m)) => commands::init::execute(m.clone()).await,
|
||||||
|
("run", Some(m)) => commands::run::execute(m.clone()).await,
|
||||||
|
("upgrade", Some(m)) => commands::upgrade::execute(m),
|
||||||
|
_ => println!("{}", usage()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage() -> &'static str {
|
||||||
|
"usage: --help to see available options.\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn banner() -> String {
|
fn banner() -> String {
|
||||||
@@ -35,6 +57,40 @@ fn banner() -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn long_version() -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
"#,
|
||||||
|
"Build Timestamp:",
|
||||||
|
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
|
"Build Version:",
|
||||||
|
env!("VERGEN_BUILD_SEMVER"),
|
||||||
|
"Commit SHA:",
|
||||||
|
env!("VERGEN_GIT_SHA"),
|
||||||
|
"Commit Date:",
|
||||||
|
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
||||||
|
"Commit Branch:",
|
||||||
|
env!("VERGEN_GIT_BRANCH"),
|
||||||
|
"rustc Version:",
|
||||||
|
env!("VERGEN_RUSTC_SEMVER"),
|
||||||
|
"rustc Channel:",
|
||||||
|
env!("VERGEN_RUSTC_CHANNEL"),
|
||||||
|
"cargo Profile:",
|
||||||
|
env!("VERGEN_CARGO_PROFILE"),
|
||||||
|
"Network:",
|
||||||
|
DEFAULT_NETWORK
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_logging() {
|
fn setup_logging() {
|
||||||
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
||||||
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub(crate) enum AuthenticationMethods {
|
|||||||
NoMethods = 0xFF,
|
NoMethods = 0xFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
/// A socks5 user with a matching password.
|
/// A socks5 user with a matching password.
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
|||||||
@@ -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
-2
@@ -24,8 +24,7 @@
|
|||||||
},
|
},
|
||||||
"../pkg": {
|
"../pkg": {
|
||||||
"name": "@nymproject/nym-client-wasm",
|
"name": "@nymproject/nym-client-wasm",
|
||||||
"version": "1.0.1",
|
"version": "0.0.1"
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
},
|
||||||
"node_modules/@discoveryjs/json-ext": {
|
"node_modules/@discoveryjs/json-ext": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// Serializable structures for what we find in common/crypto
|
// Serializable structures for what we find in common/crypto
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
pub struct PublicKey([u8; 32]);
|
pub struct PublicKey([u8; 32]);
|
||||||
|
|
||||||
impl PublicKey {
|
impl PublicKey {
|
||||||
@@ -24,7 +24,7 @@ impl AsRef<[u8]> for PublicKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
pub struct Signature([u8; 32], [u8; 32]);
|
pub struct Signature([u8; 32], [u8; 32]);
|
||||||
|
|
||||||
impl Signature {
|
impl Signature {
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::keys::PublicKey;
|
use crate::keys::PublicKey;
|
||||||
use crate::payment::LinkPaymentData;
|
use crate::payment::LinkPaymentData;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
pub struct InstantiateMsg {}
|
pub struct InstantiateMsg {}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ExecuteMsg {
|
pub enum ExecuteMsg {
|
||||||
LinkPayment { data: LinkPaymentData },
|
LinkPayment { data: LinkPaymentData },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
GetPayments {
|
GetPayments {
|
||||||
@@ -25,6 +25,6 @@ pub enum QueryMsg {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct MigrateMsg {}
|
pub struct MigrateMsg {}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::keys::{PublicKey, Signature};
|
use crate::keys::{PublicKey, Signature};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
pub struct Payment {
|
pub struct Payment {
|
||||||
verification_key: PublicKey,
|
verification_key: PublicKey,
|
||||||
gateway_identity: PublicKey,
|
gateway_identity: PublicKey,
|
||||||
@@ -27,7 +27,7 @@ impl Payment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
pub struct LinkPaymentData {
|
pub struct LinkPaymentData {
|
||||||
pub verification_key: PublicKey,
|
pub verification_key: PublicKey,
|
||||||
pub gateway_identity: PublicKey,
|
pub gateway_identity: PublicKey,
|
||||||
@@ -51,7 +51,7 @@ impl LinkPaymentData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
pub struct PagedPaymentResponse {
|
pub struct PagedPaymentResponse {
|
||||||
pub payments: Vec<Payment>,
|
pub payments: Vec<Payment>,
|
||||||
pub per_page: usize,
|
pub per_page: usize,
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ 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]
|
||||||
@@ -38,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"
|
||||||
@@ -81,4 +74,4 @@ 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 = ["web3/wasm", "web3/http", "web3/signing"]
|
wasm = ["web3/wasm", "web3/http", "web3/signing"]
|
||||||
default = ["web3/default"]
|
default = ["web3/default"]
|
||||||
@@ -1,49 +1,47 @@
|
|||||||
// 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::error::GatewayClientError;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use crate::wasm_storage::Storage;
|
use crate::wasm_storage::{Storage, StorageError};
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
use coconut_interface::Base58;
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use credential_storage::error::StorageError;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use credential_storage::storage::Storage;
|
use credential_storage::storage::Storage;
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", feature = "coconut"))]
|
|
||||||
use crate::wasm_storage::StorageError;
|
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
|
|
||||||
use credential_storage::error::StorageError;
|
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(feature = "coconut")]
|
||||||
use {
|
use credentials::coconut::{
|
||||||
coconut_interface::Base58,
|
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
|
||||||
credentials::coconut::{
|
};
|
||||||
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
|
#[cfg(not(feature = "coconut"))]
|
||||||
},
|
use credentials::token::bandwidth::TokenCredential;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use crypto::asymmetric::identity;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use 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,
|
||||||
|
};
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use pemstore::traits::PemStorableKeyPair;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use secp256k1::SecretKey;
|
||||||
|
use std::str::FromStr;
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
use web3::{
|
||||||
|
contract::{Contract, Options},
|
||||||
|
ethabi::Token,
|
||||||
|
signing::{Key, SecretKeyRef},
|
||||||
|
transports::Http,
|
||||||
|
types::{Address, U256, U64},
|
||||||
|
Web3,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
use crate::error::GatewayClientError;
|
||||||
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"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
|
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||||
|
|||||||
@@ -30,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"))]
|
||||||
@@ -67,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 {
|
||||||
@@ -86,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,
|
||||||
@@ -98,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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,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;
|
||||||
|
|
||||||
@@ -145,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,
|
||||||
@@ -168,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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,31 +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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fuse()
|
|
||||||
};
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
tokio::pin!(shutdown);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
let mut shutdown = Box::pin(async {}.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);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,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,34 +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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fuse()
|
|
||||||
};
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
tokio::pin!(shutdown);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
let mut shutdown = Box::pin(async {}.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() => {
|
||||||
@@ -138,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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -194,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.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ futures = "0.3"
|
|||||||
|
|
||||||
coconut-interface = { path = "../../coconut-interface" }
|
coconut-interface = { path = "../../coconut-interface" }
|
||||||
network-defaults = { path = "../../network-defaults" }
|
network-defaults = { path = "../../network-defaults" }
|
||||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests", features = ["coconut"] }
|
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
|
||||||
|
|
||||||
# required for nymd-client
|
# required for nymd-client
|
||||||
# at some point it might be possible to make it wasm-compatible
|
# at some point it might be possible to make it wasm-compatible
|
||||||
@@ -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,23 +2,27 @@
|
|||||||
// 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::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
use coconut_interface::{
|
||||||
use url::Url;
|
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
||||||
use validator_api_requests::coconut::{
|
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
||||||
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse, VerificationKeyResponse,
|
|
||||||
VerifyCredentialBody, VerifyCredentialResponse,
|
VerifyCredentialBody, VerifyCredentialResponse,
|
||||||
};
|
};
|
||||||
|
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use validator_api_requests::models::{
|
use validator_api_requests::models::{
|
||||||
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||||
StakeSaturationResponse,
|
StakeSaturationResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse};
|
use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse};
|
||||||
|
|
||||||
|
#[cfg(feature = "nymd-client")]
|
||||||
|
use network_defaults::DEFAULT_NETWORK;
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use crate::nymd::{
|
use crate::nymd::{
|
||||||
self, error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
@@ -28,18 +32,18 @@ use mixnet_contract_common::{
|
|||||||
RewardedSetUpdateDetails,
|
RewardedSetUpdateDetails,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use network_defaults::NymNetworkDetails;
|
|
||||||
#[cfg(feature = "nymd-client")]
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
network: network_defaults::all::Network,
|
||||||
api_url: Url,
|
api_url: Url,
|
||||||
nymd_url: Url,
|
nymd_url: Url,
|
||||||
|
mixnet_contract_address: cosmrs::AccountId,
|
||||||
nymd_config: nymd::Config,
|
vesting_contract_address: cosmrs::AccountId,
|
||||||
|
bandwidth_claim_contract_address: cosmrs::AccountId,
|
||||||
|
|
||||||
mixnode_page_limit: Option<u32>,
|
mixnode_page_limit: Option<u32>,
|
||||||
gateway_page_limit: Option<u32>,
|
gateway_page_limit: Option<u32>,
|
||||||
@@ -49,44 +53,42 @@ pub struct Config {
|
|||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn try_from_nym_network_details(
|
pub fn new(network: network_defaults::all::Network, nymd_url: Url, api_url: Url) -> Self {
|
||||||
details: &NymNetworkDetails,
|
Config {
|
||||||
) -> Result<Self, ValidatorClientError> {
|
network,
|
||||||
let mut api_url = details
|
nymd_url,
|
||||||
.endpoints
|
mixnet_contract_address: DEFAULT_NETWORK
|
||||||
.iter()
|
.mixnet_contract_address()
|
||||||
.filter_map(|d| d.api_url.as_ref())
|
|
||||||
.map(|url| Url::parse(url))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
if api_url.is_empty() {
|
|
||||||
return Err(ValidatorClientError::NoAPIUrlAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Config {
|
|
||||||
api_url: api_url.pop().unwrap(),
|
|
||||||
nymd_url: details.endpoints[0]
|
|
||||||
.nymd_url
|
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(ValidatorClientError::MalformedUrlProvided)?,
|
.expect("Error parsing mixnet contract address"),
|
||||||
nymd_config: nymd::Config::try_from_nym_network_details(details)?,
|
vesting_contract_address: DEFAULT_NETWORK
|
||||||
|
.vesting_contract_address()
|
||||||
|
.parse()
|
||||||
|
.expect("Error parsing vesting contract address"),
|
||||||
|
bandwidth_claim_contract_address: DEFAULT_NETWORK
|
||||||
|
.bandwidth_claim_contract_address()
|
||||||
|
.parse()
|
||||||
|
.expect("Error parsing bandwidth claim contract address"),
|
||||||
|
api_url,
|
||||||
mixnode_page_limit: None,
|
mixnode_page_limit: None,
|
||||||
gateway_page_limit: None,
|
gateway_page_limit: None,
|
||||||
mixnode_delegations_page_limit: None,
|
mixnode_delegations_page_limit: None,
|
||||||
rewarded_set_page_limit: None,
|
rewarded_set_page_limit: None,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this method shouldn't really exist as all information should be included immediately
|
pub fn with_mixnode_contract_address(mut self, address: cosmrs::AccountId) -> Self {
|
||||||
// via `from_nym_network_details`, but it's here for, you guessed it, legacy compatibility
|
self.mixnet_contract_address = address;
|
||||||
pub fn with_urls(mut self, nymd_url: Url, api_url: Url) -> Self {
|
|
||||||
self.nymd_url = nymd_url;
|
|
||||||
self.api_url = api_url;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_nymd_url(mut self, nymd_url: Url) -> Self {
|
pub fn with_vesting_contract_address(mut self, address: cosmrs::AccountId) -> Self {
|
||||||
self.nymd_url = nymd_url;
|
self.vesting_contract_address = address;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_bandwidth_claim_contract_address(mut self, address: cosmrs::AccountId) -> Self {
|
||||||
|
self.bandwidth_claim_contract_address = address;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +115,10 @@ impl Config {
|
|||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
pub struct Client<C> {
|
pub struct Client<C> {
|
||||||
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
pub network: network_defaults::all::Network,
|
||||||
// non-trivial amount of work and it's out of scope of the current branch
|
mixnet_contract_address: cosmrs::AccountId,
|
||||||
|
vesting_contract_address: cosmrs::AccountId,
|
||||||
|
bandwidth_claim_contract_address: cosmrs::AccountId,
|
||||||
mnemonic: Option<bip39::Mnemonic>,
|
mnemonic: Option<bip39::Mnemonic>,
|
||||||
|
|
||||||
mixnode_page_limit: Option<u32>,
|
mixnode_page_limit: Option<u32>,
|
||||||
@@ -135,18 +139,25 @@ impl Client<SigningNymdClient> {
|
|||||||
) -> 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());
|
||||||
let nymd_client = NymdClient::connect_with_mnemonic(
|
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||||
config.nymd_config.clone(),
|
config.network,
|
||||||
config.nymd_url.as_str(),
|
config.nymd_url.as_str(),
|
||||||
mnemonic.clone(),
|
mnemonic.clone(),
|
||||||
None,
|
None,
|
||||||
)?;
|
)?
|
||||||
|
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
|
||||||
|
.with_vesting_contract_address(config.vesting_contract_address.clone())
|
||||||
|
.with_bandwidth_claim_contract_address(config.bandwidth_claim_contract_address.clone());
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
|
network: config.network,
|
||||||
|
mixnet_contract_address: config.mixnet_contract_address,
|
||||||
|
vesting_contract_address: config.vesting_contract_address,
|
||||||
|
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
|
||||||
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,
|
||||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
rewarded_set_page_limit: None,
|
||||||
validator_api: validator_api_client,
|
validator_api: validator_api_client,
|
||||||
nymd: nymd_client,
|
nymd: nymd_client,
|
||||||
})
|
})
|
||||||
@@ -154,11 +165,14 @@ impl Client<SigningNymdClient> {
|
|||||||
|
|
||||||
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||||
self.nymd = NymdClient::connect_with_mnemonic(
|
self.nymd = NymdClient::connect_with_mnemonic(
|
||||||
self.nymd.current_config().clone(),
|
self.network,
|
||||||
new_endpoint.as_ref(),
|
new_endpoint.as_ref(),
|
||||||
self.mnemonic.clone().unwrap(),
|
self.mnemonic.clone().unwrap(),
|
||||||
None,
|
None,
|
||||||
)?;
|
)?
|
||||||
|
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
|
||||||
|
.with_vesting_contract_address(self.vesting_contract_address.clone())
|
||||||
|
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,10 +185,15 @@ impl Client<SigningNymdClient> {
|
|||||||
impl Client<QueryNymdClient> {
|
impl Client<QueryNymdClient> {
|
||||||
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
pub fn new_query(config: Config) -> 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_url.as_str())?
|
||||||
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
|
||||||
|
.with_vesting_contract_address(config.vesting_contract_address.clone());
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
|
network: config.network,
|
||||||
|
mixnet_contract_address: config.mixnet_contract_address,
|
||||||
|
vesting_contract_address: config.vesting_contract_address,
|
||||||
|
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
|
||||||
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,
|
||||||
@@ -186,7 +205,10 @@ impl Client<QueryNymdClient> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||||
self.nymd = NymdClient::connect(self.nymd.current_config().clone(), new_endpoint.as_ref())?;
|
self.nymd = NymdClient::connect(new_endpoint.as_ref())?
|
||||||
|
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
|
||||||
|
.with_vesting_contract_address(self.vesting_contract_address.clone())
|
||||||
|
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,12 +222,11 @@ impl<C> Client<C> {
|
|||||||
// 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) {
|
||||||
self.nymd
|
self.mixnet_contract_address = mixnet_contract_address
|
||||||
.set_mixnet_contract_address(mixnet_contract_address)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
|
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
|
||||||
self.nymd.mixnet_contract_address().clone()
|
self.mixnet_contract_address.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||||
@@ -297,13 +318,6 @@ impl<C> Client<C> {
|
|||||||
Ok(self.nymd.get_current_epoch().await?)
|
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>
|
pub async fn get_mixnet_contract_version(&self) -> Result<MixnetContractVersion, NymdError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync,
|
C: CosmWasmClient + Sync,
|
||||||
@@ -720,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,
|
||||||
@@ -733,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,5 +1,5 @@
|
|||||||
use crate::nymd::error::NymdError;
|
use crate::nymd::error::NymdError;
|
||||||
use crate::nymd::{Config as ClientConfig, NymdClient, QueryNymdClient};
|
use crate::nymd::{NymdClient, QueryNymdClient};
|
||||||
use crate::ApiClient;
|
use crate::ApiClient;
|
||||||
use network_defaults::all::Network;
|
use network_defaults::all::Network;
|
||||||
|
|
||||||
@@ -54,20 +54,10 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
|
|||||||
.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.details())
|
NymdClient::<QueryNymdClient>::connect(url.as_str())
|
||||||
.expect("failed to create valid nymd client config");
|
.map(|client| client.with_mixnet_contract_address(address))
|
||||||
|
.map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client)))
|
||||||
if let Ok(mut client) = NymdClient::<QueryNymdClient>::connect(config, url.as_str()) {
|
.ok()
|
||||||
// possibly redundant, but lets just leave it here
|
|
||||||
client.set_mixnet_contract_address(address);
|
|
||||||
Some(ClientForConnectionTest::Nymd(
|
|
||||||
network,
|
|
||||||
url,
|
|
||||||
Box::new(client),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let api_connection_test_clients = api_urls.map(|(network, url)| {
|
let api_connection_test_clients = api_urls.map(|(network, url)| {
|
||||||
@@ -86,7 +76,7 @@ fn extract_and_collect_results_into_map(
|
|||||||
.filter(|c| &c.url_type() == url_type)
|
.filter(|c| &c.url_type() == url_type)
|
||||||
.map(|c| {
|
.map(|c| {
|
||||||
let (network, url, result) = c.result();
|
let (network, url, result) = c.result();
|
||||||
(network.clone(), (url.clone(), *result))
|
(*network, (url.clone(), *result))
|
||||||
})
|
})
|
||||||
.into_group_map()
|
.into_group_map()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,4 @@ pub enum ValidatorClientError {
|
|||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
#[error("There was an issue with the Nymd client - {0}")]
|
#[error("There was an issue with the Nymd client - {0}")]
|
||||||
NymdError(#[from] crate::nymd::error::NymdError),
|
NymdError(#[from] crate::nymd::error::NymdError),
|
||||||
|
|
||||||
#[error("No validator API url has been provided")]
|
|
||||||
NoAPIUrlAvailable,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ use std::fmt;
|
|||||||
pub use cosmrs::Coin as CosmosCoin;
|
pub use cosmrs::Coin as CosmosCoin;
|
||||||
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq)]
|
||||||
pub struct MismatchedDenoms;
|
pub struct MismatchedDenoms;
|
||||||
|
|
||||||
// the reason the coin is created here as opposed to different place in the codebase is that
|
// the reason the coin is created here as opposed to different place in the codebase is that
|
||||||
// eventually we want to either publish the cosmwasm client separately or commit it to
|
// eventually we want to either publish the cosmwasm client separately or commit it to
|
||||||
// some other project, like cosmrs. Either way, in that case we can't really have
|
// some other project, like cosmrs. Either way, in that case we can't really have
|
||||||
// a dependency on an internal type
|
// a dependency on an internal type
|
||||||
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq)]
|
||||||
pub struct Coin {
|
pub struct Coin {
|
||||||
pub amount: u128,
|
pub amount: u128,
|
||||||
pub denom: String,
|
pub denom: String,
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user