Compare commits

..

2 Commits

Author SHA1 Message Date
mx 61610d5838 removed broken file link + updated link to correct line for default SURB amount 2023-06-30 15:43:13 +02:00
mx e31d0b27d4 pulled in renamed example file 2023-06-30 15:38:05 +02:00
178 changed files with 2492 additions and 4727 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
- name: install npm
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
+1 -7
View File
@@ -16,15 +16,9 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Setup yarn
run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build
run: yarn && yarn build && yarn build:ci
- name: Deploy branch to CI www (storybook)
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: "16"
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: "16"
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: "16"
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: "16"
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Yarn
run: npm install -g yarn
- run: yarn
@@ -0,0 +1,24 @@
name: Linting for Network Explorer (eslint/prettier)
on:
pull_request:
paths:
- 'explorer/**'
defaults:
run:
working-directory: explorer
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Setup yarn
run: npm install -g yarn
- name: Run ESLint
# GitHub should automatically annotate the PR
run: yarn && yarn lint
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Setup yarn
run: npm install -g yarn
continue-on-error: true
+1 -1
View File
@@ -152,7 +152,7 @@ jobs:
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
node-version: 16
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
+1 -1
View File
@@ -167,7 +167,7 @@ jobs:
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
node-version: 16
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
+1 -1
View File
@@ -167,7 +167,7 @@ jobs:
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
node-version: 16
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
@@ -15,22 +15,15 @@ jobs:
fail-fast: false
matrix:
platform: [macos-latest]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v2
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -88,38 +81,10 @@ jobs:
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release
name: Upload to release based on tag name
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/desktop/target/release/bundle/dmg/*.dmg
nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz*
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_$version_x64.dmg" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/dmg/nym-connect_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: MacOS
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false
matrix:
platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v2
@@ -36,7 +29,7 @@ jobs:
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -63,38 +56,10 @@ jobs:
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
retention-days: 30
- id: create-release
name: Upload to release based on tag name
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/desktop/target/release/bundle/appimage/*.AppImage
nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz*
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_$version_amd64.AppImage" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/appimage/nym-connect_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: Ubuntu
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false
matrix:
platform: [windows10]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- name: Clean up first
continue-on-error: true
@@ -49,7 +42,7 @@ jobs:
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -82,38 +75,10 @@ jobs:
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
retention-days: 30
- id: create-release
name: Upload to release based on tag name
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/desktop/target/release/bundle/msi/*.msi
nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-connect-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_$version_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/msi/nym-connect_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: Windows
secrets: inherit
+8 -174
View File
@@ -2,17 +2,17 @@ name: Publish Nym binaries
on:
workflow_dispatch:
inputs:
inputs:
add_tokio_unstable:
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
required: true
default: false
type: boolean
type: boolean
release:
types: [created]
env:
NETWORK: mainnet
NETWORK: mainnet
jobs:
publish-nym:
@@ -21,33 +21,15 @@ jobs:
fail-fast: false
matrix:
platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
netstat_hash: ${{ steps.binary-hashes.outputs.netstat_hash }}
client_version: ${{ steps.binary-versions.outputs.client_version }}
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
steps:
- uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install ripgrep libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
continue-on-error: true
- name: Sets env vars for tokio if set in manual dispatch inputs
run: |
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
@@ -80,8 +62,7 @@ jobs:
target/release/nym-cli
retention-days: 30
- id: create-release
name: Upload to release based on tag name
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
@@ -95,150 +76,3 @@ jobs:
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-binaries-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
- id: binary-hashes
name: Generate binary hashes
run: |
echo "client_hash=${{ hashFiles('target/release/nym-client') }}" >> "$GITHUB_OUTPUT"
echo "mixnode_hash=${{ hashFiles('target/release/nym-mixnode') }}" >> "$GITHUB_OUTPUT"
echo "gateway_hash=${{ hashFiles('target/release/nym-gateway') }}" >> "$GITHUB_OUTPUT"
echo "socks5_hash=${{ hashFiles('target/release/nym-socks5-client') }}" >> "$GITHUB_OUTPUT"
echo "netreq_hash=${{ hashFiles('target/release/nym-network-requester') }}" >> "$GITHUB_OUTPUT"
echo "cli_hash=${{ hashFiles('target/release/nym-cli') }}" >> "$GITHUB_OUTPUT"
echo "netstat_hash=${{ hashFiles('target/release/nym-network-statistics') }}" >> "$GITHUB_OUTPUT"
- id: binary-versions
name: Get binary versions
run: |
v=$(rg '^version = "(.*)"' -or '$1' clients/native/Cargo.toml) && echo "client_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' mixnode/Cargo.toml) && echo "mixnode_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' gateway/Cargo.toml) && echo "gateway_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' clients/socks5/Cargo.toml) && echo "socks5_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-requester/Cargo.toml) && echo "netreq_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT"
push-release-data-client:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.client_version }}
filename: nym-client
file_hash: ${{ needs.publish-nym.outputs.client_hash }}
name: Client
category: binaries
secrets: inherit
push-release-data-mixnode:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.mixnode_version }}
filename: nym-mixnode
file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }}
name: Mixnode
category: binaries
secrets: inherit
push-release-data-gateway:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.gateway_version }}
filename: nym-gateway
file_hash: ${{ needs.publish-nym.outputs.gateway_hash }}
name: Gateway
category: binaries
secrets: inherit
push-release-data-socks5:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.socks5_version }}
filename: nym-socks5-client
file_hash: ${{ needs.publish-nym.outputs.socks5_hash }}
name: Socks5 Client
category: binaries
secrets: inherit
push-release-data-network-requester:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.netreq_version }}
filename: nym-network-requester
file_hash: ${{ needs.publish-nym.outputs.netreq_hash }}
name: Network Requester
category: binaries
secrets: inherit
push-release-data-cli:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.cli_version }}
filename: nym-cli
file_hash: ${{ needs.publish-nym.outputs.cli_hash }}
name: Cli
category: binaries
secrets: inherit
push-release-data-network-stat:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.netstat_version }}
filename: nym-network-statistics
file_hash: ${{ needs.publish-nym.outputs.netstat_hash }}
name: Network Statistics
category: binaries
secrets: inherit
+4 -38
View File
@@ -15,22 +15,15 @@ jobs:
fail-fast: false
matrix:
platform: [macos-latest]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v2
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -87,38 +80,11 @@ jobs:
if: ${{ always() }}
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release
name: Upload to release based on tag name
- 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*
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_$version_x64.dmg" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/dmg/nym-wallet_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: MacOS
secrets: inherit
@@ -1,6 +1,5 @@
name: Publish Nym Wallet (Ubuntu)
on:
workflow_dispatch:
release:
types: [created]
@@ -15,15 +14,8 @@ jobs:
fail-fast: false
matrix:
platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v2
@@ -36,7 +28,7 @@ jobs:
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -55,37 +47,9 @@ jobs:
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- id: create-release
name: Upload to release based on tag name
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: |
nym-wallet/target/release/bundle/appimage/*.AppImage
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_$version_amd64.AppImage" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/appimage/nym-wallet_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: Ubuntu
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false
matrix:
platform: [windows10]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- name: Clean up first
continue-on-error: true
@@ -49,7 +42,7 @@ jobs:
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -82,38 +75,10 @@ jobs:
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
retention-days: 30
- id: create-release
name: Upload to release based on tag name
- 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/msi/*.msi
nym-wallet/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-wallet-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_$version_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/msi/nym-wallet_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: Windows
secrets: inherit
+6 -2
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Setup yarn
run: npm install -g yarn
- name: Install Rust stable
@@ -24,7 +24,11 @@ jobs:
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
working-directory: clients/webassembly
- name: Build WASM
run: wasm-pack build
working-directory: clients/webassembly
- name: Build dependencies
run: yarn && yarn build
- name: Build storybook
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
- name: Node v16
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Install yarn for building application
run: yarn install
-211
View File
@@ -1,211 +0,0 @@
name: Push release data
env:
strapi_download_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/downloaders'
strapi_updater_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/updaters'
on:
workflow_call:
inputs:
release_tag:
required: true
description: Release tag
type: string
release_id:
required: true
description: Release ID
type: string
release_date:
required: true
description: Release date
type: string
download_base_url:
required: true
description: Download base URL
type: string
changelog_url:
required: true
description: Changelog URL
type: string
archive_url:
required: false
description: Binary archive URL
type: string
sig_url:
required: false
description: Archive signature URL
type: string
version:
required: true
description: Release version (semver)
type: string
filename:
required: true
description: Binary file name
type: string
file_hash:
required: true
description: Binary hash (sha256)
type: string
name:
required: true
description: Name
type: string
category:
required: true
description: Category
type: string
platform:
required: false
description: Platform
type: string
workflow_dispatch:
inputs:
# ⚠ since inputs are limited to 10 max for workflow_dispatch
# some properties were omitted
version:
required: true
description: Release version (semver)
type: string
default: '1.0.0'
release_id:
required: true
description: Release ID
type: string
default: '1234'
release_date:
required: true
description: Release date
type: string
default: '2023-06-26T10:09:16Z'
download_base_url:
required: true
description: Download base URL
type: string
default: 'https://github.com/nymtech/nym/releases/download/nym-wallet-v1.0.0'
changelog_url:
required: true
description: Changelog URL
type: string
default: 'https://github.com/nymtech/nym/blob/nym-wallet-v1.0.0/nym-wallet/CHANGELOG.md'
filename:
required: true
description: Binary file name
type: string
default: 'nym-wallet_1.0.0_amd64.AppImage'
file_hash:
required: true
description: Binary hash (sha256)
type: string
default: 'xxx'
name:
required: true
description: Name
type: string
default: 'Wallet'
category:
required: true
description: Category
default: 'wallet'
type: choice
options:
- wallet
- connect
- binaries
platform:
required: false
description: Platform
default: 'Ubuntu'
type: choice
options:
- Ubuntu
- Windows
- MacOS
jobs:
push-download-data:
name: Push download data to Strapi
runs-on: custom-runner-linux
steps:
- name: Release info
run: |
echo "version: ${{ inputs.version }}"
echo "tag: ${{ inputs.release_tag }}"
- id: get_sig
name: Get sig
if: ${{ inputs.sig_url != null }}
run: |
output=$(curl -LsSf ${{ inputs.sig_url }})
echo "sig=$output" >> "$GITHUB_OUTPUT"
- id: strapi-request
name: Strapi request
uses: fjogeleit/http-request-action@v1
with:
url: ${{ env.strapi_download_url }}
method: 'POST'
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
customHeaders: '{"Content-Type": "application/json"}'
data: |
{
"data": {
"releaseId": "${{ inputs.release_id }}",
"releaseDate": "${{ inputs.release_date }}",
"downloadBaseUrl": "${{ inputs.download_base_url }}",
"changelogUrl": "${{ inputs.changelog_url }}",
"version": "${{ inputs.version }}",
"filename": "${{ inputs.filename }}",
"name": "${{ inputs.name }}",
"category": "${{ inputs.category }}",
"platform": "${{ inputs.platform }}",
"sha256": "${{ inputs.file_hash }}",
"sig": "${{ steps.get_sig.outputs.sig }}"
}
}
- name: Strapi Response
run: |
echo ${{ steps.strapi-request.outputs.response }}
push-update-data:
name: Push update data to Strapi
runs-on: custom-runner-linux
# only push update data for tauri apps (desktop wallet and NC)
if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }}
steps:
- name: Release info
run: |
echo "version: ${{ inputs.version }}"
echo "tag: ${{ inputs.release_tag }}"
- id: get_sig
name: Get sig
if: ${{ inputs.sig_url != null }}
run: |
output=$(curl -LsSf ${{ inputs.sig_url }})
echo "sig=$output" >> "$GITHUB_OUTPUT"
- id: strapi-request
name: Strapi request
uses: fjogeleit/http-request-action@v1
with:
url: ${{ env.strapi_updater_url }}
method: 'POST'
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
customHeaders: '{"Content-Type": "application/json"}'
data: |
{
"data": {
"releaseId": "${{ inputs.release_id }}",
"releaseDate": "${{ inputs.release_date }}",
"downloadUrl": "${{ inputs.archive_url }}",
"changelog": "See ${{ inputs.changelog_url }} for the changelog",
"version": "${{ inputs.version }}",
"filename": "${{ inputs.filename }}",
"category": "${{ inputs.category }}",
"platform": "${{ inputs.platform }}",
"sha256": "${{ inputs.file_hash }}",
"sig": "${{ steps.get_sig.outputs.sig }}"
}
}
- name: Strapi Response
run: |
echo ${{ steps.strapi-request.outputs.response }}
-19
View File
@@ -1,19 +0,0 @@
name: Publish SDK to NPM
on:
workflow_dispatch:
defaults:
run:
working-directory: sdk/typescript/packages/sdk
jobs:
publish:
runs-on: [custom-runner-linux]
steps:
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Setup yarn
run: npm install -g yarn
+1 -1
View File
@@ -1 +1 @@
18
16
+5 -3
View File
@@ -11,7 +11,6 @@ on:
- 'nym-connect/mobile/package.json'
- 'nym-wallet/src/**'
- 'nym-wallet/package.json'
- 'explorer/**'
pull_request:
paths:
- 'ts-packages/**'
@@ -22,7 +21,6 @@ on:
- 'nym-connect/mobile/package.json'
- 'nym-wallet/src/**'
- 'nym-wallet/package.json'
- 'explorer/**'
jobs:
build:
@@ -35,7 +33,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 16
- name: Setup yarn
run: npm install -g yarn
- name: Install Rust stable
@@ -44,6 +42,10 @@ jobs:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
working-directory: clients/webassembly
- name: Build WASM
run: wasm-pack build
working-directory: clients/webassembly
- name: Install
run: yarn
- name: Build packages
Generated
+5 -10
View File
@@ -4041,12 +4041,8 @@ name = "nym-name-service-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"cw-controllers",
"cw-utils",
"nym-contracts-common",
"schemars",
"serde",
"thiserror",
]
[[package]]
@@ -4096,7 +4092,6 @@ dependencies = [
"pretty_env_logger",
"publicsuffix",
"rand 0.7.3",
"regex",
"reqwest",
"serde",
"serde_json",
@@ -5711,13 +5706,13 @@ dependencies = [
[[package]]
name = "regex"
version = "1.8.4"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.7.2",
"regex-syntax 0.7.1",
]
[[package]]
@@ -5737,9 +5732,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
[[package]]
name = "reqwest"
+3 -3
View File
@@ -15,9 +15,9 @@ The credential binary is still experimental software. The infrastructure for usi
From the project's root directory, run:
```
cargo build -p nym-credential-client
cargo build -p credential
```
which generates the `nym-credential-client` binary in `target/debug/nym-credential-client`.
which generates the `credential` binary in `target/debug/credential`.
### Running
@@ -25,7 +25,7 @@ which generates the `nym-credential-client` binary in `target/debug/nym-credenti
For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so:
```
./target/debug/nym-credential-client --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
./target/debug/credential --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
```
More information regarding how to run the binary can be found by running it with the `--help` argument.
+4 -1
View File
@@ -24,6 +24,7 @@ use std::net::IpAddr;
pub(crate) mod init;
pub(crate) mod run;
pub(crate) mod upgrade;
lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String =
@@ -50,9 +51,10 @@ pub(crate) struct Cli {
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),
/// Generate shell completions
Completions(ArgShell),
@@ -79,6 +81,7 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
match &args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::Upgrade(m) => upgrade::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
}
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::Config;
use crate::commands::try_load_current_config;
use clap::Args;
use nym_bin_common::version_checker::Version;
use std::process;
fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet");
process::exit(1)
}
#[derive(Args, Clone)]
pub(crate) struct Upgrade {
/// Id of the nym-client we want to upgrade
#[clap(long)]
id: String,
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(&config.base.client.version).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {version}. This is not supported!"
);
process::exit(1)
}
version
}
fn parse_package_version() -> Version {
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
process::exit(1)
}
version
}
fn do_upgrade(config: Config, _args: &Upgrade, package_version: &Version) {
let config_version = parse_config_version(&config);
if &config_version == package_version {
println!("You're using the most recent version!");
return;
}
unimplemented_upgrade(package_version, &config_version)
}
pub(crate) fn execute(args: &Upgrade) {
let package_version = parse_package_version();
let id = &args.id;
let existing_config = try_load_current_config(id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
if existing_config.base.client.version.is_empty() {
eprintln!("the existing configuration file does not seem to contain version number.");
process::exit(1);
}
do_upgrade(existing_config, args, &package_version)
}
+5
View File
@@ -24,6 +24,7 @@ use std::error::Error;
pub mod init;
pub(crate) mod run;
pub(crate) mod upgrade;
lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String =
@@ -54,6 +55,9 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run),
/// Try to upgrade the client
Upgrade(upgrade::Upgrade),
/// Generate shell completions
Completions(ArgShell),
@@ -80,6 +84,7 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
match &args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::Upgrade(m) => upgrade::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
}
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config;
use crate::config::Config;
use clap::Args;
use nym_bin_common::version_checker::Version;
use std::process;
fn unimplemented_upgrade(current_version: &Version, config_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {config_version} to {current_version} as it hasn't been implemented yet");
process::exit(1)
}
#[derive(Args, Clone)]
pub(crate) struct Upgrade {
/// Id of the nym-client we want to upgrade
#[clap(long)]
id: String,
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(&config.core.base.client.version).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {version}. This is not supported!"
);
process::exit(1)
}
version
}
fn parse_package_version() -> Version {
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
process::exit(1)
}
version
}
fn do_upgrade(config: Config, _args: &Upgrade, package_version: &Version) {
let config_version = parse_config_version(&config);
if &config_version == package_version {
println!("You're using the most recent version!");
return;
}
unimplemented_upgrade(package_version, &config_version)
}
pub(crate) fn execute(args: &Upgrade) {
let package_version = parse_package_version();
let id = &args.id;
let existing_config = try_load_current_config(id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
if existing_config.core.base.client.version.is_empty() {
eprintln!("the existing configuration file does not seem to contain version number.");
process::exit(1);
}
do_upgrade(existing_config, args, &package_version)
}
+1 -1
View File
@@ -1 +1 @@
18
16
-4
View File
@@ -2580,12 +2580,8 @@ name = "nym-name-service-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"cw-controllers",
"cw-utils",
"nym-contracts-common",
"schemars",
"serde",
"thiserror",
]
[[package]]
@@ -4,7 +4,7 @@ use nym_contracts_common::ContractBuildInformation;
use nym_name_service_common::{
msg::QueryMsg as NameQueryMsg,
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
Address, NameId, RegisteredName,
Address, NameEntry, NameId,
};
use serde::Deserialize;
@@ -21,7 +21,7 @@ pub trait NameServiceQueryClient {
.await
}
async fn get_name_entry(&self, name_id: NameId) -> Result<RegisteredName, NyxdError> {
async fn get_name_entry(&self, name_id: NameId) -> Result<NameEntry, NyxdError> {
self.query_name_service_contract(NameQueryMsg::NameId { name_id })
.await
}
@@ -54,14 +54,14 @@ pub trait NameServiceQueryClient {
.await
}
async fn get_all_names(&self) -> Result<Vec<RegisteredName>, NyxdError> {
async fn get_all_names(&self) -> Result<Vec<NameEntry>, NyxdError> {
let mut services = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self.get_names_paged(start_after.take(), None).await?;
let last_id = paged_response.names.last().map(|serv| serv.id);
let last_id = paged_response.names.last().map(|serv| serv.name_id);
services.append(&mut paged_response.names);
if let Some(start_after_res) = last_id {
@@ -2,8 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use nym_contracts_common::signing::MessageSignature;
use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, NameDetails, NameId, NymName};
use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, Address, NameId, NymName};
use crate::nyxd::{
coin::Coin, cosmwasm_client::types::ExecuteResult, error::NyxdError, Fee, NyxdClient,
@@ -21,17 +20,14 @@ pub trait NameServiceSigningClient {
async fn register_name(
&self,
name: NameDetails,
owner_signature: MessageSignature,
name: NymName,
address: Address,
deposit: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_name_service_contract(
fee,
NameExecuteMsg::Register {
name,
owner_signature,
},
NameExecuteMsg::Register { name, address },
vec![deposit],
)
.await
@@ -1,7 +1,6 @@
use clap::Parser;
use log::{error, info};
use nym_contracts_common::signing::MessageSignature;
use nym_name_service_common::{Address, Coin, NameDetails, NymName};
use nym_name_service_common::{Address, Coin, NymName};
use nym_validator_client::nyxd::{error::NyxdError, traits::NameServiceSigningClient};
use tap::TapFallible;
@@ -17,15 +16,9 @@ pub struct Args {
#[clap(long)]
pub nym_address: String,
#[clap(long)]
pub signature: MessageSignature,
/// Deposit to be made to the service provider directory, in curent DENOMINATION (e.g. 'unym')
#[clap(long)]
pub deposit: u128,
#[clap(long)]
pub identity_key: String,
}
pub async fn register(args: Args, client: SigningClient) -> Result<(), NyxdError> {
@@ -36,17 +29,12 @@ pub async fn register(args: Args, client: SigningClient) -> Result<(), NyxdError
let name = NymName::new(&args.name).expect("invalid name");
let address = Address::new(&args.nym_address);
let name = NameDetails {
name,
address,
identity_key: args.identity_key,
};
let denom = client.current_chain_details().mix_denom.base.as_str();
let deposit = Coin::new(args.deposit, denom);
let res = client
.register_name(name, args.signature, deposit.into(), None)
.register_name(name, address, deposit.into(), None)
.await
.tap_err(|err| error!("Failed to register name: {err:#?}"))?;
@@ -34,8 +34,8 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
table.set_header(vec!["Name Id", "Owner", "Nym Address", "Name"]);
for name_entry in res.names {
table.add_row(vec![
name_entry.id.to_string(),
name_entry.owner.to_string(),
name_entry.name_id.to_string(),
name_entry.name.owner.to_string(),
name_entry.name.address.to_string(),
name_entry.name.name.to_string(),
]);
@@ -7,9 +7,5 @@ edition = "2021"
[dependencies]
cosmwasm-std = { workspace = true }
cw-controllers = { workspace = true }
cw-utils = { workspace = true }
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
schemars = "0.8"
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
@@ -1,6 +1,6 @@
use cosmwasm_std::{Coin, Event};
use crate::RegisteredName;
use crate::{NameId, RegisteredName};
pub enum NameEventType {
Register,
@@ -34,29 +34,29 @@ pub const OWNER: &str = "owner";
pub const DEPOSIT_REQUIRED: &str = "deposit_required";
pub fn new_register_event(name: RegisteredName) -> Event {
pub fn new_register_event(name_id: NameId, name: RegisteredName) -> Event {
Event::new(NameEventType::Register)
.add_attribute(ACTION, NameEventType::Register)
.add_attribute(NAME_ID, name.id.to_string())
.add_attribute(NAME, name.name.name.to_string())
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
.add_attribute(NAME_ID, name_id.to_string())
.add_attribute(NAME, name.name.to_string())
.add_attribute(name.address.event_tag(), name.address.to_string())
.add_attribute(OWNER, name.owner.to_string())
}
pub fn new_delete_id_event(name: RegisteredName) -> Event {
pub fn new_delete_id_event(name_id: NameId, name: RegisteredName) -> Event {
Event::new(NameEventType::DeleteId)
.add_attribute(ACTION, NameEventType::DeleteId)
.add_attribute(NAME_ID, name.id.to_string())
.add_attribute(NAME, name.name.name.to_string())
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
.add_attribute(NAME_ID, name_id.to_string())
.add_attribute(NAME, name.name.to_string())
.add_attribute(name.address.event_tag(), name.address.to_string())
}
pub fn new_delete_name_event(name: RegisteredName) -> Event {
pub fn new_delete_name_event(name_id: NameId, name: RegisteredName) -> Event {
Event::new(NameEventType::DeleteId)
.add_attribute(ACTION, NameEventType::DeleteName)
.add_attribute(NAME_ID, name.id.to_string())
.add_attribute(NAME, name.name.name.to_string())
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
.add_attribute(NAME_ID, name_id.to_string())
.add_attribute(NAME, name.name.to_string())
.add_attribute(name.address.event_tag(), name.address.to_string())
}
pub fn new_update_deposit_required_event(deposit_required: Coin) -> Event {
@@ -1,8 +1,6 @@
pub mod error;
pub mod events;
pub mod msg;
pub mod response;
pub mod signing_types;
pub mod types;
// Re-export all types at the top-level
@@ -1,6 +1,5 @@
use crate::{Address, NameDetails, NameId, NymName};
use crate::{Address, NameId, NymName};
use cosmwasm_std::Coin;
use nym_contracts_common::signing::MessageSignature;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
@@ -23,10 +22,7 @@ pub struct MigrateMsg {}
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
/// Announcing a name pointing to a nym-address
Register {
name: NameDetails,
owner_signature: MessageSignature,
},
Register { name: NymName, address: Address },
/// Delete a name entry by id
DeleteId { name_id: NameId },
/// Delete a name entry by name
@@ -42,11 +38,8 @@ impl ExecuteMsg {
pub fn default_memo(&self) -> String {
match self {
ExecuteMsg::Register {
name,
owner_signature: _,
} => {
format!("registering {} as name: {}", name.address, name.name)
ExecuteMsg::Register { name, address } => {
format!("registering {address} as name: {name}")
}
ExecuteMsg::DeleteId { name_id } => {
format!("deleting name with id {name_id}")
@@ -82,9 +75,6 @@ pub enum QueryMsg {
limit: Option<u32>,
start_after: Option<NameId>,
},
SigningNonce {
address: String,
},
Config {},
GetContractVersion {},
#[serde(rename = "get_cw2_contract_version")]
@@ -1,22 +1,36 @@
use crate::{NameId, RegisteredName};
use crate::{msg::ExecuteMsg, NameEntry, NameId, RegisteredName};
use cosmwasm_std::Coin;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
/// Like [`NameEntry`] but since it's a response type the name is an option depending on if
/// the name exists or not.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub struct NameEntryResponse {
pub name_id: NameId,
pub name: Option<RegisteredName>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct NamesListResponse {
pub names: Vec<RegisteredName>,
pub names: Vec<NameEntry>,
}
impl NamesListResponse {
pub fn new(names: Vec<RegisteredName>) -> NamesListResponse {
NamesListResponse { names }
pub fn new(names: Vec<(NameId, RegisteredName)>) -> NamesListResponse {
NamesListResponse {
names: names
.into_iter()
.map(|(name_id, name)| NameEntry::new(name_id, name))
.collect(),
}
}
}
impl From<&[RegisteredName]> for NamesListResponse {
fn from(names: &[RegisteredName]) -> Self {
impl From<&[NameEntry]> for NamesListResponse {
fn from(names: &[NameEntry]) -> Self {
NamesListResponse {
names: names.to_vec(),
}
@@ -26,17 +40,21 @@ impl From<&[RegisteredName]> for NamesListResponse {
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub struct PagedNamesListResponse {
pub names: Vec<RegisteredName>,
pub names: Vec<NameEntry>,
pub per_page: usize,
pub start_next_after: Option<NameId>,
}
impl PagedNamesListResponse {
pub fn new(
names: Vec<RegisteredName>,
names: Vec<(NameId, RegisteredName)>,
per_page: usize,
start_next_after: Option<NameId>,
) -> PagedNamesListResponse {
let names = names
.into_iter()
.map(|(name_id, name)| NameEntry::new(name_id, name))
.collect();
PagedNamesListResponse {
names,
per_page,
@@ -50,3 +68,12 @@ impl PagedNamesListResponse {
pub struct ConfigResponse {
pub deposit_required: Coin,
}
impl From<RegisteredName> for ExecuteMsg {
fn from(name: RegisteredName) -> Self {
ExecuteMsg::Register {
name: name.name,
address: name.address,
}
}
}
@@ -1,32 +0,0 @@
use cosmwasm_std::{Addr, Coin};
use nym_contracts_common::signing::{
ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose,
};
use serde::Serialize;
use crate::NameDetails;
pub type SignableNameRegisterMsg = SignableMessage<ContractMessageContent<NameRegister>>;
#[derive(Serialize)]
pub struct NameRegister {
name: NameDetails,
}
impl SigningPurpose for NameRegister {
fn message_type() -> MessageType {
MessageType::new("name-register")
}
}
pub fn construct_name_register_sign_payload(
nonce: Nonce,
sender: Addr,
deposit: Coin,
name: NameDetails,
) -> SignableNameRegisterMsg {
let payload = NameRegister { name };
let proxy = None;
let content = ContractMessageContent::new(sender, proxy, vec![deposit], payload);
SignableMessage::new(nonce, content)
}
@@ -1,48 +1,24 @@
use std::fmt::{Display, Formatter};
use cosmwasm_std::{Addr, Coin};
use nym_contracts_common::IdentityKey;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
/// The directory of names are indexed by [`NameId`].
/// The directory of services are indexed by [`ServiceId`].
pub type NameId = u32;
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)]
pub struct RegisteredName {
/// Unique id assigned to the registerd name.
pub id: NameId,
/// The registerd name details.
pub name: NameDetails,
/// name owner.
pub owner: Addr,
/// Block height at which the name was added.
pub block_height: u64,
/// The deposit used to announce the name.
pub deposit: Coin,
}
impl RegisteredName {
// Shortcut for getting the actual name
pub fn entry(&self) -> &NymName {
&self.name.name
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, JsonSchema)]
pub struct NameDetails {
/// The name pointing to the nym address
pub name: NymName,
/// The address of the name alias.
/// The address of the service.
pub address: Address,
/// The identity key of the registered name.
pub identity_key: IdentityKey,
/// Service owner.
pub owner: Addr,
/// Block height at which the service was added.
pub block_height: u64,
/// The deposit used to announce the service.
pub deposit: Coin,
}
/// String representation of a nym address, which is of the form
@@ -92,7 +68,6 @@ pub enum NymNameError {
InvalidName,
}
/// Defines what names are allowed
fn is_valid_name_char(c: char) -> bool {
// Normal lowercase letters
(c.is_alphabetic() && c.is_lowercase())
@@ -123,6 +98,20 @@ impl Display for NymName {
}
}
/// [`RegisterdName`] together with the assigned [`NameId`].
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct NameEntry {
pub name_id: NameId,
pub name: RegisteredName,
}
impl NameEntry {
pub fn new(name_id: NameId, name: RegisteredName) -> Self {
Self { name_id, name }
}
}
#[cfg(test)]
mod tests {
use super::NymName;
@@ -7,9 +7,9 @@ edition = "2021"
[dependencies]
cosmwasm-std = { workspace = true }
cw-controllers = { workspace = true }
cw-utils = { workspace = true }
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
schemars = "0.8"
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
cw-utils = { workspace = true }
cw-controllers = { workspace = true }
@@ -78,7 +78,7 @@ impl SocksRequest {
where
R: AsyncRead + Unpin,
{
log::trace!("read from stream socks5");
log::info!("read from stream socks5");
let mut packet = [0u8; 4];
// Read a byte from the stream and determine the version being requested
+1 -1
View File
@@ -30,7 +30,7 @@ enum TaskError {
}
// TODO: possibly we should create a `Status` trait instead of reusing `Error`
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
#[derive(thiserror::Error, Debug)]
pub enum TaskStatus {
#[error("Ready")]
Ready,
+2 -9
View File
@@ -1411,7 +1411,6 @@ name = "nym-name-service"
version = "0.1.0"
dependencies = [
"anyhow",
"bs58",
"cosmwasm-std",
"cw-controllers",
"cw-multi-test",
@@ -1419,10 +1418,8 @@ dependencies = [
"cw-utils",
"cw2",
"nym-contracts-common",
"nym-crypto",
"nym-name-service-common",
"rand 0.8.5",
"rand_chacha 0.2.2",
"rstest",
"semver",
"serde",
@@ -1435,12 +1432,8 @@ name = "nym-name-service-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"cw-controllers",
"cw-utils",
"nym-contracts-common",
"schemars",
"serde",
"thiserror",
]
[[package]]
@@ -1653,9 +1646,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.63"
version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
dependencies = [
"unicode-ident",
]
-3
View File
@@ -7,7 +7,6 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
bs58 = "0.4.0"
cosmwasm-std = { workspace = true }
cw-controllers = { workspace = true }
cw-storage-plus = { workspace = true }
@@ -25,7 +24,5 @@ vergen = { version = "=7.4.3", default-features = false, features = ["build", "g
[dev-dependencies]
anyhow = "1.0.40"
cw-multi-test = { workspace = true }
nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
rand = "0.8.5"
rand_chacha = "0.2"
rstest = "0.17.0"
-2
View File
@@ -14,5 +14,3 @@ pub const NAMES_PK_NAMESPACE: &str = "nanames";
pub const NAMES_OWNER_IDX_NAMESPACE: &str = "naowner";
pub const NAMES_ADDRESS_IDX_NAMESPACE: &str = "naaddress";
pub const NAMES_NAME_IDX_NAMESPACE: &str = "naname";
pub const SIGNING_NONCES_NAMESPACE: &str = "nasn";
+33 -167
View File
@@ -1,6 +1,6 @@
use crate::{
error::{NameServiceError, Result},
state::{self, Config},
NameServiceError, Result,
};
use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response};
use nym_name_service_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
@@ -72,10 +72,7 @@ pub fn execute(
msg: ExecuteMsg,
) -> Result<Response, NameServiceError> {
match msg {
ExecuteMsg::Register {
name,
owner_signature,
} => execute::register(deps, env, info, name, owner_signature),
ExecuteMsg::Register { name, address } => execute::register(deps, env, info, name, address),
ExecuteMsg::DeleteId { name_id } => execute::delete_id(deps, info, name_id),
ExecuteMsg::DeleteName { name } => execute::delete_name(deps, info, name),
ExecuteMsg::UpdateDepositRequired { deposit_required } => {
@@ -93,9 +90,6 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary> {
QueryMsg::All { limit, start_after } => {
to_binary(&query::query_all_paged(deps, limit, start_after)?)
}
QueryMsg::SigningNonce { address } => {
to_binary(&query::query_current_signing_nonce(deps, address)?)
}
QueryMsg::Config {} => to_binary(&query::query_config(deps)?),
QueryMsg::GetContractVersion {} => to_binary(&query::query_contract_version()),
QueryMsg::GetCW2ContractVersion {} => to_binary(&cw2::get_contract_version(deps.storage)?),
@@ -108,19 +102,16 @@ mod tests {
use super::*;
use crate::test_helpers::{
assert::{
assert_config, assert_current_nonce, assert_empty, assert_name, assert_names,
assert_not_found,
},
fixture::new_name_details_with_sign,
helpers::{get_attribute, nyms, test_rng},
assert::{assert_config, assert_empty, assert_name, assert_names, assert_not_found},
fixture::name_fixture,
helpers::{get_attribute, nyms},
};
use cosmwasm_std::{
testing::{mock_dependencies, mock_env, mock_info},
Addr, Coin,
};
use nym_name_service_common::{msg::ExecuteMsg, NameId, RegisteredName};
use nym_name_service_common::{msg::ExecuteMsg, NameEntry, NameId};
const DENOM: &str = "unym";
@@ -144,28 +135,23 @@ mod tests {
}
#[test]
fn register_fails_deposit_too_small() {
let mut rng = test_rng();
fn register_fails_incorrect_deposit() {
let mut deps = mock_dependencies();
let msg = InstantiateMsg::new(nyms(100));
let info = mock_info("creator", &[]);
let admin = info.sender.clone();
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(res.messages.len(), 0);
let deposit = nyms(99);
let owner = "steve";
let (name, owner_signature) =
new_name_details_with_sign(deps.as_mut(), &mut rng, "foo", "address", owner, deposit);
let msg = ExecuteMsg::Register {
name,
owner_signature,
};
// Register
let msg: ExecuteMsg = name_fixture().into();
let owner = name_fixture().owner.to_string();
assert_eq!(
execute(
deps.as_mut(),
mock_env(),
mock_info(owner, &[nyms(99)]),
mock_info(&owner, &[nyms(99)]),
msg.clone()
)
.unwrap_err(),
@@ -175,135 +161,34 @@ mod tests {
}
);
// Since we signed for 99unym deposit.
assert_eq!(
execute(
deps.as_mut(),
mock_env(),
mock_info(owner, &[nyms(100)]),
mock_info(&owner, &[nyms(101)]),
msg
)
.unwrap_err(),
NameServiceError::InvalidEd25519Signature,
);
}
#[test]
fn register_fails_deposit_too_large() {
let mut rng = test_rng();
let mut deps = mock_dependencies();
let msg = InstantiateMsg::new(nyms(100));
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(res.messages.len(), 0);
let deposit = nyms(101);
let owner = "steve";
let (name, owner_signature) =
new_name_details_with_sign(deps.as_mut(), &mut rng, "foo", "address", owner, deposit);
let msg = ExecuteMsg::Register {
name,
owner_signature,
};
assert_eq!(
execute(
deps.as_mut(),
mock_env(),
mock_info(owner, &[nyms(101)]),
msg.clone()
)
.unwrap_err(),
NameServiceError::TooLargeDeposit {
funds: 101u128.into(),
deposit_required: 100u128.into(),
}
);
// Since we signed for 101unym deposit.
assert_eq!(
execute(
deps.as_mut(),
mock_env(),
mock_info(owner, &[nyms(100)]),
msg
)
.unwrap_err(),
NameServiceError::InvalidEd25519Signature,
);
}
#[test]
fn register_fails_owner_mismatch() {
let mut rng = test_rng();
let mut deps = mock_dependencies();
let msg = InstantiateMsg::new(nyms(100));
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(res.messages.len(), 0);
// Setup
let deposit = nyms(100);
let owner = "steve";
let (name, owner_signature) = new_name_details_with_sign(
deps.as_mut(),
&mut rng,
"my-name",
"my-address",
owner,
deposit,
);
// Register
let msg = ExecuteMsg::Register {
name,
owner_signature,
};
assert_eq!(
execute(
deps.as_mut(),
mock_env(),
mock_info("timmy", &[nyms(100)]),
msg.clone(),
)
.unwrap_err(),
NameServiceError::InvalidEd25519Signature,
);
assert!(execute(
deps.as_mut(),
mock_env(),
mock_info("steve", &[nyms(100)]),
msg
)
.is_ok());
assert_config(deps.as_ref(), &admin, Coin::new(100, DENOM));
assert_empty(deps.as_ref());
}
#[test]
fn register_success() {
let mut rng = test_rng();
let mut deps = mock_dependencies();
let msg = InstantiateMsg::new(nyms(100));
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(res.messages.len(), 0);
// Setup
let deposit = nyms(100);
let owner = "steve";
let (name, owner_signature) = new_name_details_with_sign(
deps.as_mut(),
&mut rng,
"my-name",
"my-address",
owner,
deposit.clone(),
);
// Register
let msg = ExecuteMsg::Register {
name: name.clone(),
owner_signature,
};
let msg: ExecuteMsg = name_fixture().into();
let info = mock_info("steve", &[nyms(100)]);
let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
@@ -313,24 +198,17 @@ mod tests {
assert_eq!(id, expected_id);
assert_eq!(
get_attribute(&res, "register", "name"),
"my-name".to_string()
"my-service".to_string()
);
assert_eq!(
get_attribute(&res, "register", "nym_address"),
"my-address".to_string()
"client_id.client_key@gateway_id".to_string()
);
// Check that the nonce has been incremented, but only for the owner
assert_current_nonce(deps.as_ref(), &Addr::unchecked("steve"), 1);
assert_current_nonce(deps.as_ref(), &Addr::unchecked("timmy"), 0);
// The expected registered name
let expected_name = RegisteredName {
id: expected_id,
name,
owner: Addr::unchecked(owner),
block_height: 12345,
deposit,
let expected_name = NameEntry {
name_id: expected_id,
name: name_fixture(),
};
assert_names(deps.as_ref(), &[expected_name.clone()]);
assert_name(deps.as_ref(), &expected_name);
@@ -338,7 +216,6 @@ mod tests {
#[test]
fn delete() {
let mut rng = test_rng();
let mut deps = mock_dependencies();
let msg = InstantiateMsg::new(Coin::new(100, "unym"));
let info = mock_info("creator", &[]);
@@ -346,31 +223,16 @@ mod tests {
assert_eq!(res.messages.len(), 0);
// Register
let deposit = nyms(100);
let steve = "steve";
let (name, owner_signature) = new_name_details_with_sign(
deps.as_mut(),
&mut rng,
"my-name",
"my-address",
steve,
deposit.clone(),
);
let msg = ExecuteMsg::Register {
name: name.clone(),
owner_signature,
};
let msg: ExecuteMsg = name_fixture().into();
let info_steve = mock_info("steve", &[nyms(100)]);
execute(deps.as_mut(), mock_env(), info_steve.clone(), msg).unwrap();
assert_eq!(info_steve.sender, name_fixture().owner);
execute(deps.as_mut(), mock_env(), info_steve, msg).unwrap();
// The expected registerd name
let expected_id = 1;
let expected_name = RegisteredName {
id: expected_id,
name,
owner: Addr::unchecked(steve),
block_height: 12345,
deposit,
let expected_name = NameEntry {
name_id: expected_id,
name: name_fixture(),
};
assert_names(deps.as_ref(), &[expected_name]);
@@ -386,8 +248,12 @@ mod tests {
// Removing an non-existent name will fail
let msg = ExecuteMsg::delete_id(expected_id + 1);
let info_owner = MessageInfo {
sender: name_fixture().owner,
funds: vec![],
};
assert_eq!(
execute(deps.as_mut(), mock_env(), info_steve.clone(), msg).unwrap_err(),
execute(deps.as_mut(), mock_env(), info_owner.clone(), msg).unwrap_err(),
NameServiceError::NotFound {
name_id: expected_id + 1
}
@@ -395,7 +261,7 @@ mod tests {
// Remove as correct owner succeeds
let msg = ExecuteMsg::delete_id(expected_id);
let res = execute(deps.as_mut(), mock_env(), info_steve, msg).unwrap();
let res = execute(deps.as_mut(), mock_env(), info_owner, msg).unwrap();
assert_eq!(
get_attribute(&res, "delete_id", "name_id"),
expected_id.to_string()
+19 -70
View File
@@ -1,19 +1,15 @@
use crate::{
constants::{MAX_NUMBER_OF_NAMES_FOR_ADDRESS, MAX_NUMBER_OF_NAMES_PER_OWNER},
state, NameServiceError, Result,
error::{NameServiceError, Result},
state,
};
use cosmwasm_std::{Addr, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Response, Uint128};
use nym_contracts_common::{
signing::{MessageSignature, Verifier},
IdentityKey,
};
use nym_name_service_common::{
events::{
new_delete_id_event, new_delete_name_event, new_register_event,
new_update_deposit_required_event,
},
signing_types::construct_name_register_sign_payload,
Address, NameDetails, NameId, NymName, RegisteredName,
Address, NameId, NymName, RegisteredName,
};
use super::query;
@@ -90,54 +86,17 @@ fn return_deposit(name_to_delete: &RegisteredName) -> BankMsg {
}
}
fn verify_register_signature(
deps: Deps<'_>,
sender: Addr,
deposit: Coin,
name: NameDetails,
signature: MessageSignature,
) -> Result<()> {
// recover the public key
let public_key = decode_ed25519_identity_key(&name.identity_key)?;
// reconstruct the payload
let nonce = state::get_signing_nonce(deps.storage, sender.clone())?;
let msg = construct_name_register_sign_payload(nonce, sender, deposit, name);
if deps.api.verify_message(msg, signature, &public_key)? {
Ok(())
} else {
Err(NameServiceError::InvalidEd25519Signature)
}
}
fn decode_ed25519_identity_key(encoded: &IdentityKey) -> Result<[u8; 32]> {
let mut public_key = [0u8; 32];
let used = bs58::decode(encoded)
.into(&mut public_key)
.map_err(|err| NameServiceError::MalformedEd25519IdentityKey(err.to_string()))?;
if used != 32 {
return Err(NameServiceError::MalformedEd25519IdentityKey(
"Too few bytes provided for the public key".into(),
));
}
Ok(public_key)
}
/// Register a new name. It will be assigned a new name id.
pub fn register(
deps: DepsMut,
env: Env,
info: MessageInfo,
name: NameDetails,
owner_signature: MessageSignature,
name: NymName,
address: Address,
) -> Result<Response> {
ensure_name_not_exists(deps.as_ref(), &name.name)?;
ensure_name_not_exists(deps.as_ref(), &name)?;
ensure_max_names_per_owner(deps.as_ref(), info.sender.clone())?;
ensure_max_names_per_address(deps.as_ref(), name.address.clone())?;
ensure_max_names_per_address(deps.as_ref(), address.clone())?;
let deposit_required = state::deposit_required(deps.storage)?;
let denom = deposit_required.denom.clone();
@@ -145,29 +104,16 @@ pub fn register(
.map_err(|err| NameServiceError::DepositRequired { source: err })?;
ensure_correct_deposit(will_deposit, deposit_required.amount)?;
let deposit = Coin::new(will_deposit.u128(), denom);
verify_register_signature(
deps.as_ref(),
info.sender.clone(),
deposit.clone(),
name.clone(),
owner_signature,
)?;
state::increment_signing_nonce(deps.storage, info.sender.clone())?;
let id = state::next_name_id_counter(deps.storage)?;
let new_name = RegisteredName {
id,
address,
name,
owner: info.sender,
block_height: env.block.height,
deposit,
deposit: Coin::new(will_deposit.u128(), denom),
};
state::names::save(deps.storage, &new_name)?;
let name_id = state::names::save(deps.storage, &new_name)?;
Ok(Response::new().add_event(new_register_event(new_name)))
Ok(Response::new().add_event(new_register_event(name_id, new_name)))
}
/// Delete an exsisting name.
@@ -181,20 +127,23 @@ pub fn delete_id(deps: DepsMut, info: MessageInfo, name_id: NameId) -> Result<Re
Ok(Response::new()
.add_message(return_deposit_msg)
.add_event(new_delete_id_event(name_to_delete)))
.add_event(new_delete_id_event(name_id, name_to_delete)))
}
/// Delete an existing name by name.
pub(crate) fn delete_name(deps: DepsMut, info: MessageInfo, name: NymName) -> Result<Response> {
let name_to_delete = query::query_name(deps.as_ref(), name)?;
ensure_sender_authorized(info, &name_to_delete)?;
ensure_sender_authorized(info, &name_to_delete.name)?;
state::names::remove_id(deps.storage, name_to_delete.id)?;
let return_deposit_msg = return_deposit(&name_to_delete);
state::names::remove_id(deps.storage, name_to_delete.name_id)?;
let return_deposit_msg = return_deposit(&name_to_delete.name);
Ok(Response::new()
.add_message(return_deposit_msg)
.add_event(new_delete_name_event(name_to_delete)))
.add_event(new_delete_name_event(
name_to_delete.name_id,
name_to_delete.name,
)))
}
/// Update the deposit required to register new names
+9 -12
View File
@@ -1,17 +1,18 @@
use cosmwasm_std::Deps;
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
use nym_contracts_common::ContractBuildInformation;
use nym_name_service_common::{
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
Address, NameId, NymName, RegisteredName,
Address, NameEntry, NameId, NymName,
};
use crate::{
error::Result,
state::{self, names::PagedLoad},
Result,
};
pub fn query_id(deps: Deps, name_id: NameId) -> Result<RegisteredName> {
state::names::load_id(deps.storage, name_id)
pub fn query_id(deps: Deps, name_id: NameId) -> Result<NameEntry> {
let name = state::names::load_id(deps.storage, name_id)?;
Ok(NameEntry { name_id, name })
}
pub fn query_owner(deps: Deps, owner: String) -> Result<NamesListResponse> {
@@ -25,8 +26,9 @@ pub fn query_address(deps: Deps, address: Address) -> Result<NamesListResponse>
Ok(NamesListResponse::new(names))
}
pub fn query_name(deps: Deps, name: NymName) -> Result<RegisteredName> {
state::names::load_name(deps.storage, &name)
pub fn query_name(deps: Deps, name: NymName) -> Result<NameEntry> {
state::names::load_name_entry(deps.storage, &name)
.map(|(name_id, name)| NameEntry::new(name_id, name))
}
pub fn query_all_paged(
@@ -42,11 +44,6 @@ pub fn query_all_paged(
Ok(PagedNamesListResponse::new(names, limit, start_next_after))
}
pub fn query_current_signing_nonce(deps: Deps<'_>, address: String) -> Result<Nonce> {
let address = deps.api.addr_validate(&address)?;
state::get_signing_nonce(deps.storage, address)
}
pub fn query_config(deps: Deps) -> Result<ConfigResponse> {
let config = state::load_config(deps.storage)?;
Ok(config.into())
@@ -1,10 +1,8 @@
use cosmwasm_std::{Addr, StdError};
use cw_controllers::AdminError;
use nym_contracts_common::signing::verifier::ApiVerifierError;
use nym_name_service_common::{Address, NameId, NymName};
use thiserror::Error;
use crate::{Address, NameId, NymName};
#[derive(Error, Debug, PartialEq)]
pub enum NameServiceError {
#[error("{0}")]
@@ -49,21 +47,6 @@ pub enum NameServiceError {
error_message: String,
},
#[error("Failed to recover ed25519 public key from its base58 representation - {0}")]
MalformedEd25519IdentityKey(String),
#[error("Failed to recover ed25519 signature from its base58 representation - {0}")]
MalformedEd25519Signature(String),
#[error("Provided ed25519 signature did not verify correctly")]
InvalidEd25519Signature,
#[error("failed to verify message signature: {source}")]
SignatureVerificationFailure {
#[from]
source: ApiVerifierError,
},
#[error("duplicate entries detected for name: {name}")]
DuplicateNames { name: NymName },
@@ -71,4 +54,4 @@ pub enum NameServiceError {
NameAlreadyRegistered { name: NymName },
}
pub type Result<T, E = NameServiceError> = std::result::Result<T, E>;
pub(crate) type Result<T, E = NameServiceError> = std::result::Result<T, E>;
@@ -0,0 +1,445 @@
//! Integration tests using cw-multi-test.
use cosmwasm_std::Addr;
use nym_name_service_common::{
response::{ConfigResponse, PagedNamesListResponse},
Address, NameEntry, NymName, RegisteredName,
};
use crate::{
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
error::NameServiceError,
test_helpers::{fixture::name_entry, helpers::nyms, test_setup::TestSetup},
};
#[test]
fn instantiate_contract() {
TestSetup::new();
}
#[test]
fn query_config() {
assert_eq!(
TestSetup::new().query_config(),
ConfigResponse {
deposit_required: nyms(100),
}
);
}
#[test]
fn register_and_query_name() {
let mut setup = TestSetup::new();
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: None,
}
);
// Register a first name
let owner = Addr::unchecked("owner");
let name = NymName::new("steves-server").unwrap();
let nym_address = Address::new("nym-address");
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance(&owner), nyms(250));
setup.register(name.clone(), nym_address.clone(), owner.clone());
// Deposit is deposited to contract and deducted from owners's balance
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(setup.balance(&owner), nyms(150));
// We can query the full name list
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![NameEntry {
name_id: 1,
name: RegisteredName {
address: nym_address.clone(),
name: name.clone(),
owner: owner.clone(),
block_height: 12345,
deposit: nyms(100),
},
}],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(1),
}
);
// ... and we can query by id
assert_eq!(
setup.query_id(1),
NameEntry {
name_id: 1,
name: RegisteredName {
address: nym_address.clone(),
name: name.clone(),
owner: owner.clone(),
block_height: 12345,
deposit: nyms(100),
},
}
);
// Register a second name
let owner2 = Addr::unchecked("owner2");
let name2 = NymName::new("another_server").unwrap();
let nym_address2 = Address::new("nymAddress2");
setup.register(name2.clone(), nym_address2.clone(), owner2.clone());
assert_eq!(setup.contract_balance(), nyms(200));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
name_entry(1, name, nym_address, owner),
name_entry(2, name2, nym_address2, owner2)
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(2),
}
);
}
#[test]
fn cant_register_a_name_without_funds() {
let mut setup = TestSetup::new();
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance("owner"), nyms(250));
setup.register(
NymName::new("my_name").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(setup.balance("owner"), nyms(150));
setup.register(
NymName::new("my_name2").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
);
assert_eq!(setup.contract_balance(), nyms(200));
assert_eq!(setup.balance("owner"), nyms(50));
let res = setup
.try_register(
NymName::new("my_name3").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
)
.unwrap_err();
assert_eq!(
res.downcast::<cosmwasm_std::StdError>().unwrap(),
cosmwasm_std::StdError::Overflow {
source: cosmwasm_std::OverflowError::new(
cosmwasm_std::OverflowOperation::Sub,
"50",
"100"
)
}
);
}
#[test]
fn delete_name() {
let mut setup = TestSetup::new();
setup.register(
NymName::new("my_name").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(setup.balance("owner"), nyms(150));
assert!(!setup.query_all().names.is_empty());
setup.delete(1, Addr::unchecked("owner"));
// Deleting the name returns the deposit to the owner
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance("owner"), nyms(250));
assert!(setup.query_all().names.is_empty());
}
#[test]
fn only_owner_can_delete_name() {
let mut setup = TestSetup::new();
assert_eq!(setup.contract_balance(), nyms(0));
setup.register(
NymName::new("name").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert!(!setup.query_all().names.is_empty());
let delete_resp = setup
.try_delete(1, Addr::unchecked("not_owner"))
.unwrap_err();
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(
delete_resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::Unauthorized {
sender: Addr::unchecked("not_owner")
}
);
}
#[test]
fn cant_delete_name_that_does_not_exist() {
let mut setup = TestSetup::new();
setup.register(
NymName::new("foo").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert!(!setup.query_all().names.is_empty());
let delete_resp = setup.try_delete(0, Addr::unchecked("owner")).unwrap_err();
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(
delete_resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::NotFound { name_id: 0 }
);
let delete_resp = setup.try_delete(2, Addr::unchecked("owner")).unwrap_err();
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(
delete_resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::NotFound { name_id: 2 }
);
assert!(!setup.query_all().names.is_empty());
setup.delete(1, Addr::unchecked("owner"));
assert_eq!(setup.contract_balance(), nyms(0));
assert!(setup.query_all().names.is_empty());
}
#[test]
fn cant_register_the_same_name_multiple_times() {
let mut setup = TestSetup::new();
setup.register(
NymName::new("name").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
);
let resp = setup
.try_register(
NymName::new("name").unwrap(),
Address::new("nymAddress"),
Addr::unchecked("owner"),
)
.unwrap_err();
assert_eq!(
resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::NameAlreadyRegistered {
name: NymName::new("name").unwrap()
}
);
}
#[test]
fn can_register_multiple_names_for_the_same_nym_address() {
let mut setup = TestSetup::new();
let name1 = NymName::new("name1").unwrap();
let name2 = NymName::new("name2").unwrap();
let address = Address::new("nymaddress");
let owner = Addr::unchecked("owner");
setup.register(name1.clone(), address.clone(), owner.clone());
setup.register(name2.clone(), address.clone(), owner.clone());
assert_eq!(
setup.query_all().names,
vec![
name_entry(1, name1, address.clone(), owner.clone()),
name_entry(2, name2, address, owner)
],
);
}
#[test]
fn register_multiple_names_and_deleting_by_name() {
let mut setup = TestSetup::new();
let owner1 = Addr::unchecked("wealthy_owner_1");
let owner2 = Addr::unchecked("wealthy_owner_2");
let nym_address1 = Address::new("nymaddress1");
let nym_address2 = Address::new("nymaddress2");
let name1 = NymName::new("name1").unwrap();
let name2 = NymName::new("name2").unwrap();
let name3 = NymName::new("name3").unwrap();
let name4 = NymName::new("name4").unwrap();
let name5 = NymName::new("name5").unwrap();
// We register the same address three times, but with different owners
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance(&owner1), nyms(1000));
setup.register(name1.clone(), nym_address1.clone(), owner1.clone());
setup.register(name2.clone(), nym_address1.clone(), owner1.clone());
setup.register(name3.clone(), nym_address2.clone(), owner1.clone());
setup.register(name4.clone(), nym_address1.clone(), owner2.clone());
setup.register(name5.clone(), nym_address2.clone(), owner2.clone());
assert_eq!(setup.contract_balance(), nyms(500));
assert_eq!(setup.balance(&owner1), nyms(700));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
name_entry(1, name1.clone(), nym_address1.clone(), owner1.clone()),
name_entry(2, name2.clone(), nym_address1.clone(), owner1.clone()),
name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()),
name_entry(4, name4.clone(), nym_address1.clone(), owner2.clone()),
name_entry(5, name5.clone(), nym_address2.clone(), owner2.clone()),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(5),
}
);
setup.delete_name(name1, owner1.clone());
assert_eq!(setup.contract_balance(), nyms(400));
assert_eq!(setup.balance(&owner1), nyms(800));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
name_entry(2, name2, nym_address1.clone(), owner1.clone()),
name_entry(3, name3, nym_address2.clone(), owner1),
name_entry(4, name4, nym_address1, owner2.clone()),
name_entry(5, name5, nym_address2, owner2),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(5),
}
);
}
#[test]
fn check_paging() {
let mut setup = TestSetup::new();
let owner1 = Addr::unchecked("wealthy_owner_1");
let owner2 = Addr::unchecked("wealthy_owner_2");
let nym_address1 = Address::new("nymAddress1");
let nym_address2 = Address::new("nymAddress2");
let name1 = NymName::new("name1").unwrap();
let name2 = NymName::new("name2").unwrap();
let name3 = NymName::new("name3").unwrap();
let name4 = NymName::new("name4").unwrap();
let name5 = NymName::new("name5").unwrap();
// We register the same address three times, but with different owners
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance(&owner1), nyms(1000));
setup.register(name1.clone(), nym_address1.clone(), owner1.clone());
setup.register(name2.clone(), nym_address1.clone(), owner1.clone());
setup.register(name3.clone(), nym_address2.clone(), owner1.clone());
setup.register(name4.clone(), nym_address1.clone(), owner2.clone());
setup.register(name5.clone(), nym_address2.clone(), owner2.clone());
assert_eq!(setup.contract_balance(), nyms(500));
assert_eq!(setup.balance(&owner1), nyms(700));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
name_entry(1, name1.clone(), nym_address1.clone(), owner1.clone()),
name_entry(2, name2.clone(), nym_address1.clone(), owner1.clone()),
name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()),
name_entry(4, name4.clone(), nym_address1.clone(), owner2.clone()),
name_entry(5, name5, nym_address2.clone(), owner2.clone()),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(5),
}
);
setup.delete_name(name1, owner1.clone());
assert_eq!(
setup.query_all_with_limit(Some(2), None),
PagedNamesListResponse {
names: vec![
name_entry(2, name2, nym_address1.clone(), owner1.clone()),
name_entry(3, name3.clone(), nym_address2.clone(), owner1.clone()),
],
per_page: 2,
start_next_after: Some(3),
}
);
assert_eq!(
setup.query_all_with_limit(Some(2), Some(2)),
PagedNamesListResponse {
names: vec![
name_entry(3, name3, nym_address2, owner1),
name_entry(4, name4, nym_address1, owner2),
],
per_page: 2,
start_next_after: Some(4),
}
);
}
#[test]
fn name_id_is_not_resused_when_deleting_and_then_adding_a_new_names() {
let mut setup = TestSetup::new();
setup.register(
NymName::new("myname1").unwrap(),
Address::new("nymAddress1"),
Addr::unchecked("owner1"),
);
setup.register(
NymName::new("myname2").unwrap(),
Address::new("nymAddress2"),
Addr::unchecked("owner2"),
);
setup.register(
NymName::new("myname3").unwrap(),
Address::new("nymAddress3"),
Addr::unchecked("owner3"),
);
setup.delete(1, Addr::unchecked("owner1"));
setup.delete(3, Addr::unchecked("owner3"));
assert_eq!(
setup.query_all().names,
vec![name_entry(
2,
NymName::new("myname2").unwrap(),
Address::new("nymAddress2"),
Addr::unchecked("owner2")
)]
);
setup.register(
NymName::new("myname4").unwrap(),
Address::new("nymAddress4"),
Addr::unchecked("owner4"),
);
assert_eq!(
setup.query_all().names,
vec![
name_entry(
2,
NymName::new("myname2").unwrap(),
Address::new("nymAddress2"),
Addr::unchecked("owner2")
),
name_entry(
4,
NymName::new("myname4").unwrap(),
Address::new("nymAddress4"),
Addr::unchecked("owner4")
)
]
);
}
@@ -1,148 +0,0 @@
use cosmwasm_std::Addr;
use nym_name_service_common::{response::PagedNamesListResponse, Address, NymName};
use rstest::rstest;
use crate::{
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
test_helpers::{fixture::new_name, helpers::nyms},
NameServiceError,
};
use super::test_setup::TestSetup;
#[rstest::fixture]
fn setup() -> TestSetup {
TestSetup::new()
}
#[rstest]
fn delete_name(mut setup: TestSetup) {
setup.sign_and_register(
&NymName::new("my_name").unwrap(),
&Address::new("address"),
&Addr::unchecked("owner"),
&nyms(100),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(setup.balance("owner"), nyms(150));
assert!(!setup.query_all().names.is_empty());
setup.delete(1, Addr::unchecked("owner"));
// Deleting the name returns the deposit to the owner
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance("owner"), nyms(250));
assert!(setup.query_all().names.is_empty());
}
#[rstest]
fn only_owner_can_delete_name(mut setup: TestSetup) {
assert_eq!(setup.contract_balance(), nyms(0));
setup.sign_and_register(
&NymName::new("name").unwrap(),
&Address::new("nymAddress"),
&Addr::unchecked("owner"),
&nyms(100),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert!(!setup.query_all().names.is_empty());
let delete_resp = setup
.try_delete(1, Addr::unchecked("not_owner"))
.unwrap_err();
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(
delete_resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::Unauthorized {
sender: Addr::unchecked("not_owner")
}
);
}
#[rstest]
fn cant_delete_name_that_does_not_exist(mut setup: TestSetup) {
setup.sign_and_register(
&NymName::new("foo").unwrap(),
&Address::new("nymAddress"),
&Addr::unchecked("owner"),
&nyms(100),
);
assert_eq!(setup.contract_balance(), nyms(100));
assert!(!setup.query_all().names.is_empty());
let delete_resp = setup.try_delete(0, Addr::unchecked("owner")).unwrap_err();
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(
delete_resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::NotFound { name_id: 0 }
);
let delete_resp = setup.try_delete(2, Addr::unchecked("owner")).unwrap_err();
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(
delete_resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::NotFound { name_id: 2 }
);
assert!(!setup.query_all().names.is_empty());
setup.delete(1, Addr::unchecked("owner"));
assert_eq!(setup.contract_balance(), nyms(0));
assert!(setup.query_all().names.is_empty());
}
#[rstest]
fn register_multiple_names_and_deleting_by_name(mut setup: TestSetup) {
let owner1 = Addr::unchecked("wealthy_owner_1");
let owner2 = Addr::unchecked("wealthy_owner_2");
let address1 = Address::new("address1");
let address2 = Address::new("address2");
let name1 = NymName::new("name1").unwrap();
let name2 = NymName::new("name2").unwrap();
let name3 = NymName::new("name3").unwrap();
let name4 = NymName::new("name4").unwrap();
let name5 = NymName::new("name5").unwrap();
// We register the same address three times, but with different owners
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance(&owner1), nyms(1000));
let s1 = setup.sign_and_register(&name1, &address1, &owner1, &nyms(100));
let s2 = setup.sign_and_register(&name2, &address1, &owner1, &nyms(100));
let s3 = setup.sign_and_register(&name3, &address2, &owner1, &nyms(100));
let s4 = setup.sign_and_register(&name4, &address1, &owner2, &nyms(100));
let s5 = setup.sign_and_register(&name5, &address2, &owner2, &nyms(100));
assert_eq!(setup.contract_balance(), nyms(500));
assert_eq!(setup.balance(&owner1), nyms(700));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
new_name(1, &name1, &address1, &owner1, s1.identity_key()),
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
new_name(5, &name5, &address2, &owner2, s5.identity_key()),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(5),
}
);
setup.delete_name(name1, owner1.clone());
assert_eq!(setup.contract_balance(), nyms(400));
assert_eq!(setup.balance(&owner1), nyms(800));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
new_name(5, &name5, &address2, &owner2, s5.identity_key()),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(5),
}
);
}
@@ -1,13 +0,0 @@
//! Integration tests using cw-multi-test.
mod delete;
mod name_id;
mod query;
mod register;
mod test_name;
mod test_setup;
#[test]
fn instantiate_contract() {
test_setup::TestSetup::new();
}
@@ -1,70 +0,0 @@
use cosmwasm_std::Addr;
use nym_name_service_common::{Address, NymName};
use crate::test_helpers::{fixture::new_name, helpers::nyms};
use super::test_setup::TestSetup;
#[test]
fn name_id_is_not_resused_when_deleting_and_then_adding_a_new_names() {
let mut setup = TestSetup::new();
setup.sign_and_register(
&NymName::new("myname1").unwrap(),
&Address::new("nymAddress1"),
&Addr::unchecked("owner1"),
&nyms(100),
);
let s2 = setup.sign_and_register(
&NymName::new("myname2").unwrap(),
&Address::new("nymAddress2"),
&Addr::unchecked("owner2"),
&nyms(100),
);
setup.sign_and_register(
&NymName::new("myname3").unwrap(),
&Address::new("nymAddress3"),
&Addr::unchecked("owner3"),
&nyms(100),
);
setup.delete(1, Addr::unchecked("owner1"));
setup.delete(3, Addr::unchecked("owner3"));
assert_eq!(
setup.query_all().names,
vec![new_name(
2,
&NymName::new("myname2").unwrap(),
&Address::new("nymAddress2"),
&Addr::unchecked("owner2"),
s2.identity_key(),
)]
);
let s4 = setup.sign_and_register(
&NymName::new("myname4").unwrap(),
&Address::new("nymAddress4"),
&Addr::unchecked("owner4"),
&nyms(100),
);
assert_eq!(
setup.query_all().names,
vec![
new_name(
2,
&NymName::new("myname2").unwrap(),
&Address::new("nymAddress2"),
&Addr::unchecked("owner2"),
s2.identity_key(),
),
new_name(
4,
&NymName::new("myname4").unwrap(),
&Address::new("nymAddress4"),
&Addr::unchecked("owner4"),
s4.identity_key(),
)
]
);
}
@@ -1,88 +0,0 @@
use cosmwasm_std::Addr;
use nym_name_service_common::{
response::{ConfigResponse, PagedNamesListResponse},
Address, NymName,
};
use crate::{
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
test_helpers::{fixture::new_name, helpers::nyms},
};
use super::test_setup::TestSetup;
#[test]
fn query_config() {
assert_eq!(
TestSetup::new().query_config(),
ConfigResponse {
deposit_required: nyms(100),
}
);
}
#[test]
fn check_paging() {
let mut setup = TestSetup::new();
let owner1 = Addr::unchecked("wealthy_owner_1");
let owner2 = Addr::unchecked("wealthy_owner_2");
let address1 = Address::new("nymAddress1");
let address2 = Address::new("nymAddress2");
let name1 = NymName::new("name1").unwrap();
let name2 = NymName::new("name2").unwrap();
let name3 = NymName::new("name3").unwrap();
let name4 = NymName::new("name4").unwrap();
let name5 = NymName::new("name5").unwrap();
// We register the same address three times, but with different owners
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance(&owner1), nyms(1000));
let s1 = setup.sign_and_register(&name1, &address1, &owner1, &nyms(100));
let s2 = setup.sign_and_register(&name2, &address1, &owner1, &nyms(100));
let s3 = setup.sign_and_register(&name3, &address2, &owner1, &nyms(100));
let s4 = setup.sign_and_register(&name4, &address1, &owner2, &nyms(100));
let s5 = setup.sign_and_register(&name5, &address2, &owner2, &nyms(100));
assert_eq!(setup.contract_balance(), nyms(500));
assert_eq!(setup.balance(&owner1), nyms(700));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
new_name(1, &name1, &address1, &owner1, s1.identity_key()),
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
new_name(5, &name5, &address2, &owner2, s5.identity_key()),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(5),
}
);
setup.delete_name(name1, owner1.clone());
assert_eq!(
setup.query_all_with_limit(Some(2), None),
PagedNamesListResponse {
names: vec![
new_name(2, &name2, &address1, &owner1, s2.identity_key()),
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
],
per_page: 2,
start_next_after: Some(3),
}
);
assert_eq!(
setup.query_all_with_limit(Some(2), Some(2)),
PagedNamesListResponse {
names: vec![
new_name(3, &name3, &address2, &owner1, s3.identity_key()),
new_name(4, &name4, &address1, &owner2, s4.identity_key()),
],
per_page: 2,
start_next_after: Some(4),
}
);
}
@@ -1,269 +0,0 @@
use cosmwasm_std::Addr;
use nym_name_service_common::{
error::NameServiceError, response::PagedNamesListResponse, Address, NameDetails, NymName,
RegisteredName,
};
use rstest::rstest;
use crate::{
constants::NAME_DEFAULT_RETRIEVAL_LIMIT,
test_helpers::{fixture::new_name, helpers::nyms},
};
use super::test_setup::TestSetup;
#[rstest::fixture]
fn setup() -> TestSetup {
TestSetup::new()
}
#[rstest]
fn basic_register(mut setup: TestSetup) {
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: None,
}
);
// Register a first name
let owner = Addr::unchecked("owner");
let name = NymName::new("steves-server").unwrap();
let nym_address = Address::new("nym-address");
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance(&owner), nyms(250));
assert_eq!(setup.query_signing_nonce(owner.to_string()), 0);
let reg_name = setup.new_name(&name, &nym_address);
let payload = setup.payload_to_sign(&owner, &nyms(100), &reg_name.name);
let reg_name = reg_name.sign(payload);
setup.register(&reg_name, &owner);
// Deposit is deposited to contract and deducted from owners's balance
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(setup.balance(&owner), nyms(150));
// The signing nonce has been incremented
assert_eq!(setup.query_signing_nonce(owner.to_string()), 1);
// We can query the full name list
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![RegisteredName {
id: 1,
name: NameDetails {
name: name.clone(),
address: nym_address.clone(),
identity_key: reg_name.identity_key().to_string(),
},
owner: owner.clone(),
block_height: 12345,
deposit: nyms(100),
}],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(1),
}
);
// ... and we can query by id
assert_eq!(
setup.query_id(1),
RegisteredName {
id: 1,
name: reg_name.details().clone(),
owner: owner.clone(),
block_height: 12345,
deposit: nyms(100),
}
);
// Register a second name
let owner2 = Addr::unchecked("owner2");
let name2 = NymName::new("another_server").unwrap();
let nym_address2 = Address::new("nymAddress2");
let reg_name2 = setup.new_signed_name(&name2, &nym_address2, &owner2, &nyms(100));
setup.register(&reg_name2, &owner2);
assert_eq!(setup.contract_balance(), nyms(200));
assert_eq!(
setup.query_all(),
PagedNamesListResponse {
names: vec![
new_name(1, &name, &nym_address, &owner, reg_name.identity_key()),
new_name(2, &name2, &nym_address2, &owner2, reg_name2.identity_key()),
],
per_page: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(2),
}
);
}
#[rstest]
fn register_fails_when_owner_mismatch(mut setup: TestSetup) {
let owner = Addr::unchecked("owner");
let name = NymName::new("steves-server").unwrap();
let nym_address = Address::new("nym-address");
let reg_name = setup.new_signed_name(&name, &nym_address, &owner, &nyms(100));
let res = setup
.try_register(&reg_name, &Addr::unchecked("owner2"))
.unwrap_err();
assert_eq!(
res.downcast::<NameServiceError>().unwrap(),
NameServiceError::InvalidEd25519Signature
);
}
#[rstest]
fn signing_nonce_is_increased_when_registering(mut setup: TestSetup) {
let owner1 = Addr::unchecked("owner1");
let owner2 = Addr::unchecked("owner2");
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 0);
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 0);
setup.sign_and_register(
&NymName::new("myname1").unwrap(),
&Address::new("address1"),
&owner1,
&nyms(100),
);
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1);
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 0);
setup.sign_and_register(
&NymName::new("myname2").unwrap(),
&Address::new("address2"),
&owner2,
&nyms(100),
);
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1);
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 1);
setup.sign_and_register(
&NymName::new("myname3").unwrap(),
&Address::new("address3"),
&owner2,
&nyms(100),
);
assert_eq!(setup.query_signing_nonce(owner1.to_string()), 1);
assert_eq!(setup.query_signing_nonce(owner2.to_string()), 2);
}
#[rstest]
fn creating_two_names_in_a_row_without_announcing_fails(mut setup: TestSetup) {
let owner = Addr::unchecked("wealthy_owner_1");
let name1 = NymName::new("steves-server1").unwrap();
let name2 = NymName::new("steves-server2").unwrap();
let address1 = Address::new("nymAddress1");
let address2 = Address::new("nymAddress2");
let deposit = nyms(100);
let s1 = setup.new_signed_name(&name1, &address1, &owner, &deposit);
// This second name will be signed with the same nonce
let s2 = setup.new_signed_name(&name2, &address2, &owner, &deposit);
// Announce the first service works, and this increments the nonce
setup.register(&s1, &owner);
// Now the nonce has been incremented, and the signature will not match
let resp: NameServiceError = setup
.try_register(&s2, &owner)
.unwrap_err()
.downcast()
.unwrap();
assert_eq!(resp, NameServiceError::InvalidEd25519Signature,);
}
#[rstest]
fn cant_register_a_name_without_funds(mut setup: TestSetup) {
assert_eq!(setup.contract_balance(), nyms(0));
assert_eq!(setup.balance("owner"), nyms(250));
let name1 = setup.new_signed_name(
&NymName::new("my_name").unwrap(),
&Address::new("nymAddress"),
&Addr::unchecked("owner"),
&nyms(100),
);
setup.register(&name1, &Addr::unchecked("owner"));
assert_eq!(setup.contract_balance(), nyms(100));
assert_eq!(setup.balance("owner"), nyms(150));
let name2 = setup.new_signed_name(
&NymName::new("my_name2").unwrap(),
&Address::new("nymAddress"),
&Addr::unchecked("owner"),
&nyms(100),
);
setup.register(&name2, &Addr::unchecked("owner"));
assert_eq!(setup.contract_balance(), nyms(200));
assert_eq!(setup.balance("owner"), nyms(50));
let name3 = setup.new_signed_name(
&NymName::new("my_name3").unwrap(),
&Address::new("nymAddress"),
&Addr::unchecked("owner"),
&nyms(100),
);
let res = setup
.try_register(&name3, &Addr::unchecked("owner"))
.unwrap_err();
assert_eq!(
res.downcast::<cosmwasm_std::StdError>().unwrap(),
cosmwasm_std::StdError::Overflow {
source: cosmwasm_std::OverflowError::new(
cosmwasm_std::OverflowOperation::Sub,
"50",
"100"
)
}
);
}
#[rstest]
fn cant_register_the_same_name_multiple_times(mut setup: TestSetup) {
let name1 = setup.new_signed_name(
&NymName::new("name").unwrap(),
&Address::new("nymAddress"),
&Addr::unchecked("owner"),
&nyms(100),
);
setup.register(&name1, &Addr::unchecked("owner"));
let resp = setup
.try_register(&name1, &Addr::unchecked("owner"))
.unwrap_err();
assert_eq!(
resp.downcast::<NameServiceError>().unwrap(),
NameServiceError::NameAlreadyRegistered {
name: NymName::new("name").unwrap()
}
);
}
#[rstest]
fn can_register_multiple_names_for_the_same_nym_address(mut setup: TestSetup) {
let name1 = NymName::new("name1").unwrap();
let name2 = NymName::new("name2").unwrap();
let address = Address::new("nymaddress");
let owner = Addr::unchecked("owner");
let reg_name1 = setup.new_signed_name(&name1, &address, &owner, &nyms(100));
setup.register(&reg_name1, &owner);
let reg_name2 = setup.new_signed_name(&name2, &address, &owner, &nyms(100));
setup.register(&reg_name2, &owner);
assert_eq!(
setup.query_all().names,
vec![
new_name(1, &name1, &address, &owner, reg_name1.identity_key()),
new_name(2, &name2, &address, &owner, reg_name2.identity_key()),
],
);
}
//
@@ -1,75 +0,0 @@
use nym_contracts_common::{signing::MessageSignature, IdentityKey};
use nym_crypto::asymmetric::identity;
use nym_name_service_common::{
signing_types::SignableNameRegisterMsg, Address, NameDetails, NymName,
};
use rand_chacha::ChaCha20Rng;
use crate::test_helpers::signing::ed25519_sign_message;
pub struct TestName {
pub name: NameDetails,
pub keys: identity::KeyPair,
pub rng: ChaCha20Rng,
}
impl TestName {
pub fn new(rng: &mut ChaCha20Rng, name: NymName, address: Address) -> Self {
let keys = identity::KeyPair::new(rng);
let name = NameDetails {
name,
address,
identity_key: keys.public_key().to_base58_string(),
};
Self {
name,
keys,
rng: rng.clone(),
}
}
pub fn identity_key(&self) -> &IdentityKey {
&self.name.identity_key
}
pub fn details(&self) -> &NameDetails {
&self.name
}
pub fn sign(self, payload: SignableNameRegisterMsg) -> SignedTestName {
let owner_signature = ed25519_sign_message(payload, self.keys.private_key());
SignedTestName {
name: self.name,
keys: self.keys,
owner_signature,
}
}
}
impl From<TestName> for NameDetails {
fn from(test_name: TestName) -> Self {
test_name.name
}
}
pub struct SignedTestName {
pub name: NameDetails,
pub keys: identity::KeyPair,
pub owner_signature: MessageSignature,
}
impl SignedTestName {
pub fn identity_key(&self) -> &IdentityKey {
&self.name.identity_key
}
pub fn details(&self) -> &NameDetails {
&self.name
}
}
impl From<SignedTestName> for NameDetails {
fn from(signed_name: SignedTestName) -> Self {
signed_name.name
}
}
+3 -2
View File
@@ -3,15 +3,16 @@
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
pub use nym_name_service_common::error::{NameServiceError, Result};
use crate::error::Result;
use nym_name_service_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response};
use error::NameServiceError;
mod contract;
mod error;
mod state;
pub mod constants;
+1 -1
View File
@@ -1,7 +1,7 @@
use cosmwasm_std::{Addr, Deps, DepsMut};
use cw_controllers::Admin;
use crate::{constants::ADMIN_KEY, Result};
use crate::{constants::ADMIN_KEY, error::Result};
const ADMIN: Admin = Admin::new(ADMIN_KEY);
+1 -1
View File
@@ -3,7 +3,7 @@ use cw_storage_plus::Item;
use nym_name_service_common::response::ConfigResponse;
use serde::{Deserialize, Serialize};
use crate::{constants::CONFIG_KEY, Result};
use crate::{constants::CONFIG_KEY, error::Result};
const CONFIG: Item<Config> = Item::new(CONFIG_KEY);
-2
View File
@@ -2,9 +2,7 @@ pub mod admin;
pub mod config;
pub mod name_id_counter;
pub mod names;
pub mod nonce;
pub(crate) use admin::{assert_admin, set_admin};
pub(crate) use config::{deposit_required, load_config, save_config, Config};
pub(crate) use name_id_counter::next_name_id_counter;
pub(crate) use nonce::{get_signing_nonce, increment_signing_nonce};
@@ -2,7 +2,7 @@ use cosmwasm_std::Storage;
use cw_storage_plus::Item;
use nym_name_service_common::NameId;
use crate::{constants::NAME_ID_COUNTER_KEY, Result};
use crate::{constants::NAME_ID_COUNTER_KEY, error::Result};
const NAME_ID_COUNTER: Item<NameId> = Item::new(NAME_ID_COUNTER_KEY);
@@ -16,56 +16,33 @@ pub(crate) fn next_name_id_counter(store: &mut dyn Storage) -> Result<NameId> {
#[cfg(test)]
mod tests {
use cosmwasm_std::Addr;
use nym_name_service_common::RegisteredName;
use nym_name_service_common::NameEntry;
use crate::test_helpers::{
assert::assert_names,
helpers::{nyms, test_rng},
transactions::{delete_name_id, instantiate_test_contract, register_name},
fixture::name_fixture_name,
helpers::{delete_name_id, instantiate_test_contract, register_name},
};
#[test]
fn get_next_name_id() {
let mut deps = instantiate_test_contract();
let mut rng = test_rng();
let (id1, name1) = register_name(deps.as_mut(), &mut rng, "foo", "addr1", "steve");
let (id2, name2) = register_name(deps.as_mut(), &mut rng, "bar", "addr2", "steve");
let (id3, name3) = register_name(deps.as_mut(), &mut rng, "baz", "addr3", "steve");
assert_eq!(id1, 1);
assert_eq!(id2, 2);
assert_eq!(id3, 3);
assert_eq!(name1.name.as_str(), "foo");
assert_eq!(name1.address.as_str(), "addr1");
assert_eq!(name2.name.as_str(), "bar");
assert_eq!(name2.address.as_str(), "addr2");
assert_eq!(name3.name.as_str(), "baz");
assert_eq!(name3.address.as_str(), "addr3");
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("foo")), 1);
assert_names(
deps.as_ref(),
&[NameEntry::new(1, name_fixture_name("foo"))],
);
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("bar")), 2);
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("baz")), 3);
assert_names(
deps.as_ref(),
&[
RegisteredName {
id: 1,
name: name1,
owner: Addr::unchecked("steve"),
block_height: 12345,
deposit: nyms(100),
},
RegisteredName {
id: 2,
name: name2,
owner: Addr::unchecked("steve"),
block_height: 12345,
deposit: nyms(100),
},
RegisteredName {
id: 3,
name: name3,
owner: Addr::unchecked("steve"),
block_height: 12345,
deposit: nyms(100),
},
NameEntry::new(1, name_fixture_name("foo")),
NameEntry::new(2, name_fixture_name("bar")),
NameEntry::new(3, name_fixture_name("baz")),
],
);
}
@@ -73,28 +50,34 @@ mod tests {
#[test]
fn deleted_name_id_is_not_reused() {
let mut deps = instantiate_test_contract();
let mut rng = test_rng();
// Register two names
let (_, name1) = register_name(deps.as_mut(), &mut rng, "one", "sdfjkhsdfhr", "steve");
register_name(deps.as_mut(), &mut rng, "two", "suereljer", "steve");
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("one")), 1);
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("two")), 2);
assert_names(
deps.as_ref(),
&[
NameEntry::new(1, name_fixture_name("one")),
NameEntry::new(2, name_fixture_name("two")),
],
);
// Delete the last entry
delete_name_id(deps.as_mut(), 2, "steve");
assert_names(
deps.as_ref(),
&[RegisteredName {
id: 1,
name: name1,
owner: Addr::unchecked("steve"),
block_height: 12345,
deposit: nyms(100),
}],
&[NameEntry::new(1, name_fixture_name("one"))],
);
// Create a third entry. The index should not reuse the previous entry that we just
// deleted.
let (id3, _) = register_name(deps.as_mut(), &mut rng, "three", "ufd", "steve");
assert_eq!(id3, 3);
assert_eq!(register_name(deps.as_mut(), &name_fixture_name("two")), 3);
assert_names(
deps.as_ref(),
&[
NameEntry::new(1, name_fixture_name("one")),
NameEntry::new(3, name_fixture_name("two")),
],
);
}
}
+222 -159
View File
@@ -8,7 +8,7 @@ use crate::{
NAMES_ADDRESS_IDX_NAMESPACE, NAMES_NAME_IDX_NAMESPACE, NAMES_OWNER_IDX_NAMESPACE,
NAMES_PK_NAMESPACE, NAME_DEFAULT_RETRIEVAL_LIMIT, NAME_MAX_RETRIEVAL_LIMIT,
},
NameServiceError, Result,
error::{NameServiceError, Result},
};
struct NameIndex<'a> {
@@ -28,9 +28,9 @@ impl<'a> IndexList<RegisteredName> for NameIndex<'a> {
fn names<'a>() -> IndexedMap<'a, NameId, RegisteredName, NameIndex<'a>> {
let indexes = NameIndex {
name: UniqueIndex::new(|d| d.name.name.to_string(), NAMES_NAME_IDX_NAMESPACE),
name: UniqueIndex::new(|d| d.name.to_string(), NAMES_NAME_IDX_NAMESPACE),
address: MultiIndex::new(
|d| d.name.address.to_string(),
|d| d.address.to_string(),
NAMES_PK_NAMESPACE,
NAMES_ADDRESS_IDX_NAMESPACE,
),
@@ -43,29 +43,19 @@ fn names<'a>() -> IndexedMap<'a, NameId, RegisteredName, NameIndex<'a>> {
IndexedMap::new(NAMES_PK_NAMESPACE, indexes)
}
pub fn save(store: &mut dyn Storage, new_name: &RegisteredName) -> Result<()> {
let name_id = new_name.id;
pub fn save(store: &mut dyn Storage, new_name: &RegisteredName) -> Result<NameId> {
let name_id = super::next_name_id_counter(store)?;
names().save(store, name_id, new_name)?;
Ok(())
Ok(name_id)
}
#[cfg(test)]
pub fn save_all(state: &mut dyn Storage, names: &[RegisteredName]) -> Result<()> {
pub fn save_all(state: &mut dyn Storage, names: &[RegisteredName]) -> Result<Vec<NameId>> {
let mut ids = vec![];
for name in names {
save(state, name)?;
ids.push(save(state, name)?);
}
Ok(())
}
pub fn remove_id(store: &mut dyn Storage, name_id: NameId) -> Result<()> {
Ok(names().remove(store, name_id)?)
}
#[cfg(test)]
pub fn remove_name(store: &mut dyn Storage, name: NymName) -> Result<NameId> {
let registered_name = load_name(store, &name)?;
remove_id(store, registered_name.id)?;
Ok(registered_name.id)
Ok(ids)
}
pub fn has_name_id(store: &dyn Storage, name_id: NameId) -> bool {
@@ -76,6 +66,23 @@ pub fn has_name(store: &dyn Storage, name: &NymName) -> bool {
load_name(store, name).is_ok()
}
// Get the (key, name) entry for a given name
pub fn load_name_entry(store: &dyn Storage, name: &NymName) -> Result<(NameId, RegisteredName)> {
names()
.idx
.name
.range(store, None, None, Order::Ascending)
.find(|entry| {
if let Ok(entry) = entry {
&entry.1.name == name
} else {
false
}
})
.ok_or(NameServiceError::NameNotFound { name: name.clone() })?
.map_err(NameServiceError::from)
}
pub fn load_id(store: &dyn Storage, name_id: NameId) -> Result<RegisteredName> {
names().load(store, name_id).map_err(|err| match err {
StdError::NotFound { .. } => NameServiceError::NotFound { name_id },
@@ -92,33 +99,45 @@ pub fn load_name(store: &dyn Storage, name: &NymName) -> Result<RegisteredName>
.ok_or(NameServiceError::NameNotFound { name: name.clone() })
}
pub fn load_address(store: &dyn Storage, address: &Address) -> Result<Vec<RegisteredName>> {
pub fn load_address(
store: &dyn Storage,
address: &Address,
) -> Result<Vec<(NameId, RegisteredName)>> {
names()
.idx
.address
.prefix(address.to_string())
.range(store, None, None, Order::Ascending)
.take(MAX_NUMBER_OF_NAMES_FOR_ADDRESS as usize)
.map(|res| res.map(|(_, name)| name))
.collect::<StdResult<Vec<_>>>()
.map_err(NameServiceError::from)
}
pub fn load_owner(store: &dyn Storage, owner: Addr) -> Result<Vec<RegisteredName>> {
pub fn load_owner(store: &dyn Storage, owner: Addr) -> Result<Vec<(NameId, RegisteredName)>> {
names()
.idx
.owner
.prefix(owner)
.range(store, None, None, Order::Ascending)
.take(MAX_NUMBER_OF_NAMES_PER_OWNER as usize)
.map(|res| res.map(|(_, name)| name))
.collect::<StdResult<Vec<_>>>()
.map_err(NameServiceError::from)
}
pub fn remove_id(store: &mut dyn Storage, name_id: NameId) -> Result<()> {
Ok(names().remove(store, name_id)?)
}
#[cfg(test)]
pub fn remove_name(store: &mut dyn Storage, name: NymName) -> Result<NameId> {
let name_info = load_name_entry(store, &name)?;
remove_id(store, name_info.0)?;
Ok(name_info.0)
}
#[derive(Debug, PartialEq)]
pub struct PagedLoad {
pub names: Vec<RegisteredName>,
pub names: Vec<(NameId, RegisteredName)>,
pub limit: usize,
pub start_next_after: Option<NameId>,
}
@@ -137,10 +156,9 @@ pub fn load_all_paged(
let names = names()
.range(store, start, None, Order::Ascending)
.take(limit)
.map(|res| res.map(|(_, name)| name))
.collect::<StdResult<Vec<_>>>()?;
let start_next_after = names.last().map(|name| name.id);
let start_next_after = names.last().map(|name| name.0);
Ok(PagedLoad {
names,
@@ -151,6 +169,8 @@ pub fn load_all_paged(
#[cfg(test)]
mod tests {
use std::iter::zip;
use cosmwasm_std::{
testing::{MockApi, MockQuerier},
MemoryStorage, OwnedDeps,
@@ -158,11 +178,11 @@ mod tests {
use rstest::rstest;
use crate::{
error::NameServiceError,
test_helpers::{
fixture::{name_fixture, name_fixture_full},
transactions::instantiate_test_contract,
helpers::instantiate_test_contract,
},
NameServiceError,
};
use super::*;
@@ -177,55 +197,64 @@ mod tests {
#[rstest::fixture]
fn uniq_names() -> Vec<RegisteredName> {
vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_three", "owner_three"),
name_fixture_full("one", "address_one", "owner_one"),
name_fixture_full("two", "address_two", "owner_two"),
name_fixture_full("three", "address_three", "owner_three"),
]
}
#[rstest::fixture]
fn overlapping_addresses() -> Vec<RegisteredName> {
vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_two", "owner_three"),
name_fixture_full("one", "address_one", "owner_one"),
name_fixture_full("two", "address_two", "owner_two"),
name_fixture_full("three", "address_two", "owner_three"),
]
}
#[rstest::fixture]
fn overlapping_owners() -> Vec<RegisteredName> {
vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_three", "owner_two"),
name_fixture_full("one", "address_one", "owner_one"),
name_fixture_full("two", "address_two", "owner_two"),
name_fixture_full("three", "address_three", "owner_two"),
]
}
fn assert_not_registered(store: &dyn Storage, names: Vec<RegisteredName>) {
fn assert_not_registered(store: &dyn Storage, names: Vec<RegisteredName>, ids: Vec<NameId>) {
let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect();
let loaded = load_all_paged(store, None, None).unwrap();
for name in &names {
assert!(!has_name_id(store, name.id));
assert!(!has_name(store, name.entry()));
assert!(!loaded.names.iter().any(|l_name| l_name.id == name.id));
assert!(!loaded.names.iter().any(|l_name| l_name == name));
for (id, name) in &names {
assert!(!has_name_id(store, *id));
assert!(!has_name(store, &name.name));
assert!(!loaded.names.iter().any(|(i, _)| i == id));
assert!(!loaded.names.iter().any(|(_, n)| n == name));
}
}
fn assert_registered(store: &dyn Storage, names: Vec<RegisteredName>) {
fn assert_registered(store: &dyn Storage, names: Vec<RegisteredName>, ids: Vec<NameId>) {
assert!(names.len() == ids.len());
let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect();
let loaded = load_all_paged(store, None, None).unwrap();
for name in &names {
assert!(has_name_id(store, name.id));
assert!(has_name(store, name.entry()));
assert!(loaded.names.iter().filter(|n| n == &name).count() == 1);
for (id, name) in &names {
assert!(has_name_id(store, *id));
assert!(has_name(store, &name.name));
assert!(loaded.names.iter().filter(|(i, _)| i == id).count() == 1);
assert!(loaded.names.iter().filter(|(_, n)| n == name).count() == 1);
}
}
fn assert_only_these_registered(store: &dyn Storage, names: Vec<RegisteredName>) {
for name in &names {
assert!(has_name_id(store, name.id));
assert!(has_name(store, name.entry()));
fn assert_only_these_registered(
store: &dyn Storage,
names: Vec<RegisteredName>,
ids: Vec<NameId>,
) {
let last_id = *ids.last().unwrap();
let names: Vec<(NameId, RegisteredName)> = zip(ids, names).collect();
for (id, name) in &names {
assert!(has_name_id(store, *id));
assert!(has_name(store, &name.name));
}
let last_id = names.last().unwrap().id;
assert_eq!(
load_all_paged(store, None, None).unwrap(),
PagedLoad {
@@ -238,107 +267,102 @@ mod tests {
#[rstest]
fn single_basic_save_works(mut deps: TestDeps) {
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
}
#[rstest]
fn save_same_name_twice_fails(mut deps: TestDeps) {
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert!(matches!(
save(deps.as_mut().storage, &name_fixture(2)).unwrap_err(),
save(deps.as_mut().storage, &name_fixture()).unwrap_err(),
NameServiceError::Std(StdError::GenericErr { .. })
));
}
#[rstest]
fn remove_id_works(mut deps: TestDeps) {
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
assert!(has_name_id(&deps.storage, 1));
assert!(has_name(&deps.storage, name_fixture(1).entry()));
remove_id(deps.as_mut().storage, 1).unwrap();
assert!(!has_name_id(&deps.storage, 1));
assert!(!has_name(&deps.storage, name_fixture(1).entry()));
}
#[rstest]
fn remove_name_works(mut deps: TestDeps) {
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
assert!(has_name_id(&deps.storage, 1));
assert!(has_name(&deps.storage, name_fixture(1).entry()));
remove_name(deps.as_mut().storage, name_fixture(1).name.name).unwrap();
assert!(!has_name_id(&deps.storage, 1));
assert!(!has_name(&deps.storage, name_fixture(1).entry()));
}
#[rstest]
fn has_name_works(mut deps: TestDeps) {
assert!(!has_name(&deps.storage, name_fixture(1).entry()));
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
assert!(has_name(&deps.storage, name_fixture(1).entry()));
assert!(!has_name(&deps.storage, &name_fixture().name));
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert!(has_name(&deps.storage, &name_fixture().name));
}
#[rstest]
fn has_name_id_works(mut deps: TestDeps) {
assert!(!has_name_id(&deps.storage, 1));
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert!(has_name_id(&deps.storage, 1));
}
#[rstest]
fn has_name_id_with_incorrect_id_fails(mut deps: TestDeps) {
assert!(!has_name_id(&deps.storage, 2));
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert!(!has_name_id(&deps.storage, 2));
}
#[rstest]
fn load_name_entry_works(mut deps: TestDeps) {
assert_eq!(
load_name_entry(deps.as_ref().storage, &name_fixture().name).unwrap_err(),
NameServiceError::NameNotFound {
name: name_fixture().name
}
);
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert_eq!(
load_name_entry(deps.as_ref().storage, &name_fixture().name).unwrap(),
(1, name_fixture())
);
}
#[rstest]
fn load_id_works(mut deps: TestDeps) {
assert_eq!(
load_id(deps.as_ref().storage, 1).unwrap_err(),
NameServiceError::NotFound { name_id: 1 }
);
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
assert_eq!(load_id(deps.as_ref().storage, 1).unwrap(), name_fixture(1),);
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert_eq!(load_id(deps.as_ref().storage, 1).unwrap(), name_fixture(),);
}
#[rstest]
fn load_name_works(mut deps: TestDeps) {
assert_eq!(
load_name(deps.as_ref().storage, name_fixture(1).entry()).unwrap_err(),
load_name(deps.as_ref().storage, &name_fixture().name).unwrap_err(),
NameServiceError::NameNotFound {
name: name_fixture(1).name.name,
name: name_fixture().name
}
);
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert_eq!(
load_name(deps.as_ref().storage, name_fixture(1).entry()).unwrap(),
name_fixture(1),
load_name(deps.as_ref().storage, &name_fixture().name).unwrap(),
name_fixture(),
);
}
#[rstest]
fn load_address_works(mut deps: TestDeps) {
assert_eq!(
load_address(deps.as_ref().storage, &name_fixture(1).name.address).unwrap(),
load_address(deps.as_ref().storage, &name_fixture().address).unwrap(),
vec![],
);
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert_eq!(
load_address(deps.as_ref().storage, &name_fixture(1).name.address).unwrap(),
vec![name_fixture(1)],
load_address(deps.as_ref().storage, &name_fixture().address).unwrap(),
vec![(1, name_fixture())],
);
}
#[rstest]
fn load_owner_works(mut deps: TestDeps) {
assert_eq!(
load_owner(deps.as_ref().storage, name_fixture(1).owner).unwrap(),
load_owner(deps.as_ref().storage, name_fixture().owner).unwrap(),
vec![],
);
save(deps.as_mut().storage, &name_fixture(1)).unwrap();
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert_eq!(
load_owner(deps.as_ref().storage, name_fixture(1).owner).unwrap(),
vec![name_fixture(1)],
load_owner(deps.as_ref().storage, name_fixture().owner).unwrap(),
vec![(1, name_fixture())],
);
}
@@ -356,19 +380,60 @@ mod tests {
assert_eq!(
load_all_paged(&deps.storage, None, None).unwrap(),
PagedLoad {
names: vec![uniq_names[0].clone()],
names: vec![(1, uniq_names[0].clone())],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(1),
}
);
}
#[rstest]
fn remove_id_works(mut deps: TestDeps) {
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert!(has_name_id(&deps.storage, 1));
assert!(has_name(&deps.storage, &name_fixture().name));
remove_id(deps.as_mut().storage, 1).unwrap();
assert!(!has_name_id(&deps.storage, 1));
assert!(!has_name(&deps.storage, &name_fixture().name));
}
#[rstest]
fn remove_name_works(mut deps: TestDeps) {
save(deps.as_mut().storage, &name_fixture()).unwrap();
assert!(has_name_id(&deps.storage, 1));
assert!(has_name(&deps.storage, &name_fixture().name));
remove_name(deps.as_mut().storage, name_fixture().name).unwrap();
assert!(!has_name_id(&deps.storage, 1));
assert!(!has_name(&deps.storage, &name_fixture().name));
}
#[rstest]
fn save_set_of_unique_names_works(mut deps: TestDeps, uniq_names: Vec<RegisteredName>) {
assert_not_registered(&deps.storage, uniq_names.clone());
let num = uniq_names.len() as NameId;
let ids = (1..=num).collect::<Vec<NameId>>();
assert_not_registered(&deps.storage, uniq_names.clone(), ids.clone());
let saved_ids = save_all(deps.as_mut().storage, &uniq_names).unwrap();
assert_eq!(saved_ids, ids);
assert_registered(&deps.storage, uniq_names.clone(), ids.clone());
assert_only_these_registered(&deps.storage, uniq_names, ids);
}
#[rstest]
fn save_set_of_unique_names_generates_ids(mut deps: TestDeps, uniq_names: Vec<RegisteredName>) {
let num = uniq_names.len() as NameId;
let ids = save_all(deps.as_mut().storage, &uniq_names).unwrap();
assert_eq!(ids, (1..=num).collect::<Vec<NameId>>());
}
#[rstest]
fn load_name_entry_for_unique_set_works(mut deps: TestDeps, uniq_names: Vec<RegisteredName>) {
save_all(deps.as_mut().storage, &uniq_names).unwrap();
assert_registered(&deps.storage, uniq_names.clone());
assert_only_these_registered(&deps.storage, uniq_names);
for (id, name) in uniq_names.iter().enumerate() {
assert_eq!(
load_name_entry(deps.as_ref().storage, &name.name).unwrap(),
(id as NameId + 1, name.clone()),
);
}
}
#[rstest]
@@ -376,7 +441,7 @@ mod tests {
save_all(deps.as_mut().storage, &uniq_names).unwrap();
for name in uniq_names {
assert_eq!(
load_name(deps.as_ref().storage, name.entry()).unwrap(),
load_name(deps.as_ref().storage, &name.name).unwrap(),
name.clone(),
);
}
@@ -387,14 +452,17 @@ mod tests {
mut deps: TestDeps,
uniq_names: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &uniq_names).unwrap();
remove_id(deps.as_mut().storage, 2).unwrap();
let ids = save_all(deps.as_mut().storage, &uniq_names).unwrap();
remove_id(deps.as_mut().storage, ids[1]).unwrap();
assert_eq!(
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(3, "three", "address_three", "owner_three"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(
3,
name_fixture_full("three", "address_three", "owner_three")
),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -408,13 +476,16 @@ mod tests {
uniq_names: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &uniq_names).unwrap();
remove_name(deps.as_mut().storage, uniq_names[1].entry().clone()).unwrap();
remove_name(deps.as_mut().storage, uniq_names[1].name.clone()).unwrap();
assert_eq!(
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(3, "three", "address_three", "owner_three"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(
3,
name_fixture_full("three", "address_three", "owner_three")
),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -427,9 +498,9 @@ mod tests {
mut deps: TestDeps,
overlapping_addresses: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
assert_registered(&deps.storage, overlapping_addresses.clone());
assert_only_these_registered(&deps.storage, overlapping_addresses);
let ids = save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
assert_registered(&deps.storage, overlapping_addresses.clone(), ids.clone());
assert_only_these_registered(&deps.storage, overlapping_addresses, ids);
}
#[rstest]
@@ -442,9 +513,9 @@ mod tests {
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_two", "owner_three"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(2, name_fixture_full("two", "address_two", "owner_two")),
(3, name_fixture_full("three", "address_two", "owner_three")),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -453,8 +524,8 @@ mod tests {
assert_eq!(
load_address(deps.as_ref().storage, &Address::new("address_two")).unwrap(),
vec![
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_two", "owner_three"),
(2, name_fixture_full("two", "address_two", "owner_two")),
(3, name_fixture_full("three", "address_two", "owner_three")),
]
);
}
@@ -464,14 +535,14 @@ mod tests {
mut deps: TestDeps,
overlapping_addresses: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
remove_id(deps.as_mut().storage, 2).unwrap();
let ids = save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
remove_id(deps.as_mut().storage, ids[1]).unwrap();
assert_eq!(
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(3, "three", "address_two", "owner_three"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(3, name_fixture_full("three", "address_two", "owner_three")),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -485,17 +556,13 @@ mod tests {
overlapping_addresses: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &overlapping_addresses).unwrap();
remove_name(
deps.as_mut().storage,
overlapping_addresses[1].name.name.clone(),
)
.unwrap();
remove_name(deps.as_mut().storage, overlapping_addresses[1].name.clone()).unwrap();
assert_eq!(
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(3, "three", "address_two", "owner_three"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(3, name_fixture_full("three", "address_two", "owner_three")),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -508,9 +575,9 @@ mod tests {
mut deps: TestDeps,
overlapping_owners: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
assert_registered(&deps.storage, overlapping_owners.clone());
assert_only_these_registered(&deps.storage, overlapping_owners);
let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone());
assert_only_these_registered(&deps.storage, overlapping_owners, ids);
}
#[rstest]
@@ -523,9 +590,9 @@ mod tests {
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_three", "owner_two"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(2, name_fixture_full("two", "address_two", "owner_two")),
(3, name_fixture_full("three", "address_three", "owner_two")),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -534,8 +601,8 @@ mod tests {
assert_eq!(
load_owner(deps.as_ref().storage, Addr::unchecked("owner_two")).unwrap(),
vec![
name_fixture_full(2, "two", "address_two", "owner_two"),
name_fixture_full(3, "three", "address_three", "owner_two"),
(2, name_fixture_full("two", "address_two", "owner_two")),
(3, name_fixture_full("three", "address_three", "owner_two")),
]
);
}
@@ -545,16 +612,16 @@ mod tests {
mut deps: TestDeps,
overlapping_owners: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
assert_registered(&deps.storage, overlapping_owners.clone());
assert_only_these_registered(&deps.storage, overlapping_owners);
let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone());
assert_only_these_registered(&deps.storage, overlapping_owners, ids);
remove_id(deps.as_mut().storage, 2).unwrap();
assert_eq!(
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(3, "three", "address_three", "owner_two"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(3, name_fixture_full("three", "address_three", "owner_two")),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -567,16 +634,16 @@ mod tests {
mut deps: TestDeps,
overlapping_owners: Vec<RegisteredName>,
) {
save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
assert_registered(&deps.storage, overlapping_owners.clone());
assert_only_these_registered(&deps.storage, overlapping_owners.clone());
remove_name(deps.as_mut().storage, overlapping_owners[1].entry().clone()).unwrap();
let ids = save_all(deps.as_mut().storage, &overlapping_owners).unwrap();
assert_registered(&deps.storage, overlapping_owners.clone(), ids.clone());
assert_only_these_registered(&deps.storage, overlapping_owners.clone(), ids);
remove_name(deps.as_mut().storage, overlapping_owners[1].name.clone()).unwrap();
assert_eq!(
load_all_paged(deps.as_ref().storage, None, None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(3, "three", "address_three", "owner_two"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(3, name_fixture_full("three", "address_three", "owner_two")),
],
limit: NAME_DEFAULT_RETRIEVAL_LIMIT as usize,
start_next_after: Some(3),
@@ -591,8 +658,8 @@ mod tests {
load_all_paged(&deps.storage, Some(2), None).unwrap(),
PagedLoad {
names: vec![
name_fixture_full(1, "one", "address_one", "owner_one"),
name_fixture_full(2, "two", "address_two", "owner_two"),
(1, name_fixture_full("one", "address_one", "owner_one")),
(2, name_fixture_full("two", "address_two", "owner_two")),
],
limit: 2,
start_next_after: Some(2),
@@ -601,12 +668,10 @@ mod tests {
assert_eq!(
load_all_paged(&deps.storage, Some(1), Some(2)).unwrap(),
PagedLoad {
names: vec![name_fixture_full(
names: vec![(
3,
"three",
"address_three",
"owner_three"
)],
name_fixture_full("three", "address_three", "owner_three")
),],
limit: 1,
start_next_after: Some(3),
}
@@ -614,12 +679,10 @@ mod tests {
assert_eq!(
load_all_paged(&deps.storage, Some(2), Some(2)).unwrap(),
PagedLoad {
names: vec![name_fixture_full(
names: vec![(
3,
"three",
"address_three",
"owner_three"
)],
name_fixture_full("three", "address_three", "owner_three")
),],
limit: 2,
start_next_after: Some(3),
}
-71
View File
@@ -1,71 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{constants::SIGNING_NONCES_NAMESPACE, Result};
use cosmwasm_std::{Addr, Storage};
use cw_storage_plus::Map;
use nym_contracts_common::signing::Nonce;
pub const NONCES: Map<'_, Addr, Nonce> = Map::new(SIGNING_NONCES_NAMESPACE);
pub fn get_signing_nonce(storage: &dyn Storage, address: Addr) -> Result<Nonce> {
let nonce = NONCES.may_load(storage, address)?.unwrap_or(0);
Ok(nonce)
}
fn update_signing_nonce(storage: &mut dyn Storage, address: Addr, value: Nonce) -> Result<()> {
NONCES
.save(storage, address, &value)
.map_err(|err| err.into())
}
pub fn increment_signing_nonce(storage: &mut dyn Storage, address: Addr) -> Result<()> {
// get the current nonce
let nonce = get_signing_nonce(storage, address.clone())?;
// increment it for the next use
update_signing_nonce(storage, address, nonce + 1)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::transactions::instantiate_test_contract;
use cosmwasm_std::{
testing::{MockApi, MockQuerier},
MemoryStorage, OwnedDeps,
};
use rstest::rstest;
type TestDeps = OwnedDeps<MemoryStorage, MockApi, MockQuerier>;
#[rstest::fixture]
fn deps() -> TestDeps {
instantiate_test_contract()
}
fn addr(s: &str) -> Addr {
Addr::unchecked(s)
}
#[rstest]
fn getting_signing_nonce_doesnt_increment_it(deps: TestDeps) {
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0);
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0);
}
#[rstest]
fn increment_works(mut deps: TestDeps) {
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 0);
increment_signing_nonce(&mut deps.storage, addr("gunnar")).unwrap();
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 1);
}
#[rstest]
fn incrementing_is_independent(mut deps: TestDeps) {
increment_signing_nonce(&mut deps.storage, addr("gunnar")).unwrap();
assert_eq!(get_signing_nonce(&deps.storage, addr("gunnar")).unwrap(), 1);
assert_eq!(get_signing_nonce(&deps.storage, addr("bjorn")).unwrap(), 0);
}
}
@@ -1,12 +1,11 @@
use cosmwasm_std::{from_binary, testing::mock_env, Addr, Coin, Deps};
use nym_contracts_common::signing::Nonce;
use nym_name_service_common::{
msg::QueryMsg,
response::{ConfigResponse, PagedNamesListResponse},
NameId, RegisteredName,
NameEntry, NameId,
};
use crate::{constants::NAME_DEFAULT_RETRIEVAL_LIMIT, NameServiceError};
use crate::{constants::NAME_DEFAULT_RETRIEVAL_LIMIT, error::NameServiceError};
pub fn assert_config(deps: Deps, admin: &Addr, deposit_required: Coin) {
crate::state::assert_admin(deps, admin).unwrap();
@@ -15,10 +14,10 @@ pub fn assert_config(deps: Deps, admin: &Addr, deposit_required: Coin) {
assert_eq!(config, ConfigResponse { deposit_required });
}
pub fn assert_names(deps: Deps, expected_names: &[RegisteredName]) {
pub fn assert_names(deps: Deps, expected_names: &[NameEntry]) {
let res = crate::contract::query(deps, mock_env(), QueryMsg::all()).unwrap();
let names: PagedNamesListResponse = from_binary(&res).unwrap();
let start_next_after = expected_names.iter().last().map(|s| s.id);
let start_next_after = expected_names.iter().last().map(|s| s.name_id);
assert_eq!(
names,
PagedNamesListResponse {
@@ -29,16 +28,16 @@ pub fn assert_names(deps: Deps, expected_names: &[RegisteredName]) {
);
}
pub fn assert_name(deps: Deps, expected_name: &RegisteredName) {
pub fn assert_name(deps: Deps, expected_name: &NameEntry) {
let res = crate::contract::query(
deps,
mock_env(),
QueryMsg::NameId {
name_id: expected_name.id,
name_id: expected_name.name_id,
},
)
.unwrap();
let names: RegisteredName = from_binary(&res).unwrap();
let names: NameEntry = from_binary(&res).unwrap();
assert_eq!(&names, expected_name);
}
@@ -64,16 +63,3 @@ pub fn assert_not_found(deps: Deps, expected_id: NameId) {
}
));
}
pub fn assert_current_nonce(deps: Deps, address: &Addr, expected_nonce: Nonce) {
let res = crate::contract::query(
deps,
mock_env(),
QueryMsg::SigningNonce {
address: address.to_string(),
},
)
.unwrap();
let nonce: Nonce = from_binary(&res).unwrap();
assert_eq!(nonce, expected_nonce);
}
@@ -1,103 +1,29 @@
use cosmwasm_std::{Addr, Coin, DepsMut};
use nym_contracts_common::{signing::MessageSignature, IdentityKeyRef};
use nym_crypto::asymmetric::identity;
use nym_name_service_common::{Address, NameDetails, NameId, NymName, RegisteredName};
use rand_chacha::rand_core::{CryptoRng, RngCore};
use cosmwasm_std::Addr;
use nym_name_service_common::{Address, NameEntry, NameId, NymName, RegisteredName};
use super::{
helpers::nyms,
signing::{ed25519_sign_message, name_register_sign_payload},
};
use super::helpers::nyms;
pub fn new_name(
name_id: NameId,
name: &NymName,
address: &Address,
owner: &Addr,
identity_key: IdentityKeyRef,
) -> RegisteredName {
pub fn name_fixture_full(name: &str, nym_address: &str, owner: &str) -> RegisteredName {
RegisteredName {
id: name_id,
name: NameDetails {
name: name.clone(),
address: address.clone(),
identity_key: identity_key.to_string(),
},
owner: owner.clone(),
name: NymName::new(name).unwrap(),
address: Address::new(nym_address),
owner: Addr::unchecked(owner),
block_height: 12345,
deposit: nyms(100),
}
}
pub fn name_fixture(id: NameId) -> RegisteredName {
new_name(
id,
&NymName::new("my-service").unwrap(),
&Address::new("client_id.client_key@gateway_id"),
&Addr::unchecked("steve"),
"identity",
)
pub fn name_fixture() -> RegisteredName {
name_fixture_full("my-service", "client_id.client_key@gateway_id", "steve")
}
#[allow(unused)]
pub fn name_fixture_with_name(id: NameId, name: &str, address: &str) -> RegisteredName {
new_name(
id,
&NymName::new(name).unwrap(),
&Address::new(address),
&Addr::unchecked("steve"),
"identity",
)
pub fn name_fixture_name(name: &str) -> RegisteredName {
name_fixture_full(name, "client_id.client_key@gateway_id", "steve")
}
pub fn name_fixture_full(id: NameId, name: &str, address: &str, owner: &str) -> RegisteredName {
new_name(
id,
&NymName::new(name).unwrap(),
&Address::new(address),
&Addr::unchecked(owner),
"identity",
)
}
// Create a new name, using a correctly generted identity key
pub fn new_name_details<R>(
rng: &mut R,
name: &str,
nym_address: &str,
) -> (NameDetails, identity::KeyPair)
where
R: RngCore + CryptoRng,
{
let keypair = identity::KeyPair::new(rng);
(
NameDetails {
name: NymName::new(name).unwrap(),
address: Address::new(nym_address),
identity_key: keypair.public_key().to_base58_string(),
},
keypair,
)
}
// Create a new service, with a correctly generated identity key, and sign it
pub fn new_name_details_with_sign<R>(
deps: DepsMut<'_>,
rng: &mut R,
name: &str,
nym_address: &str,
owner: &str,
deposit: Coin,
) -> (NameDetails, MessageSignature)
where
R: RngCore + CryptoRng,
{
// Service
let (name, keypair) = new_name_details(rng, name, nym_address);
// Sign
let sign_msg = name_register_sign_payload(deps.as_ref(), owner, name.clone(), deposit);
let owner_signature = ed25519_sign_message(sign_msg, keypair.private_key());
(name, owner_signature)
pub fn name_entry(name_id: NameId, name: NymName, address: Address, owner: Addr) -> NameEntry {
NameEntry {
name_id,
name: name_fixture_full(name.as_str(), address.as_str(), owner.as_str()),
}
}
@@ -1,16 +1,19 @@
use cosmwasm_std::{Coin, Event, Response};
use cosmwasm_std::{
coin, coins,
testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier},
Coin, DepsMut, Event, MemoryStorage, OwnedDeps, Response,
};
use cw_multi_test::AppResponse;
use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
use nym_name_service_common::{
events::{NameEventType, NAME_ID},
msg::{ExecuteMsg, InstantiateMsg},
NameId, NymName, RegisteredName,
};
pub fn nyms(amount: u64) -> Coin {
Coin::new(amount.into(), "unym")
}
pub fn test_rng() -> ChaCha20Rng {
let dummy_seed = [42u8; 32];
ChaCha20Rng::from_seed(dummy_seed)
}
pub fn get_event_types(response: &Response, event_type: &str) -> Vec<Event> {
response
.events
@@ -52,3 +55,53 @@ pub fn get_app_attribute(response: &AppResponse, event_type: &str, key: &str) ->
.value
.clone()
}
#[allow(unused)]
pub fn get_app_attributes(response: &AppResponse, event_type: &str, key: &str) -> Vec<String> {
get_app_event_types(response, event_type)
.iter()
.map(|ev| {
ev.attributes
.iter()
.find(|attr| attr.key == key)
.unwrap()
.value
.clone()
})
.collect::<Vec<_>>()
}
pub fn instantiate_test_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
deposit_required: coin(100, "unym"),
};
let env = mock_env();
let info = mock_info("creator", &[]);
let res = crate::instantiate(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(res.messages.len(), 0);
deps
}
pub fn register_name(deps: DepsMut<'_>, name: &RegisteredName) -> NameId {
let msg: ExecuteMsg = name.clone().into();
let info = mock_info(name.owner.as_str(), &coins(100, "unym"));
let res = crate::execute(deps, mock_env(), info, msg).unwrap();
let name_id: NameId = get_attribute(&res, &NameEventType::Register.to_string(), NAME_ID)
.parse()
.unwrap();
name_id
}
pub fn delete_name_id(deps: DepsMut<'_>, name_id: NameId, owner: &str) {
let msg = ExecuteMsg::DeleteId { name_id };
let info = mock_info(owner, &[]);
crate::execute(deps, mock_env(), info, msg).unwrap();
}
#[allow(unused)]
pub fn delete_name(deps: DepsMut<'_>, name: NymName, owner: &str) {
let msg = ExecuteMsg::DeleteName { name };
let info = mock_info(owner, &[]);
crate::execute(deps, mock_env(), info, msg).unwrap();
}
@@ -1,5 +1,4 @@
pub mod assert;
pub mod fixture;
pub mod helpers;
pub mod signing;
pub mod transactions;
pub mod test_setup;
@@ -1,39 +0,0 @@
use cosmwasm_std::{Addr, Coin, Deps};
use nym_contracts_common::signing::{
MessageSignature, SignableMessage, SigningAlgorithm, SigningPurpose,
};
use nym_crypto::asymmetric::identity;
use nym_name_service_common::{
signing_types::{construct_name_register_sign_payload, SignableNameRegisterMsg},
NameDetails,
};
use serde::Serialize;
use crate::state;
pub fn name_register_sign_payload(
deps: Deps<'_>,
owner: &str,
name: NameDetails,
deposit: Coin,
) -> SignableNameRegisterMsg {
let owner = Addr::unchecked(owner);
let nonce = state::get_signing_nonce(deps.storage, owner.clone()).unwrap();
construct_name_register_sign_payload(nonce, owner, deposit, name)
}
pub fn ed25519_sign_message<T: Serialize + SigningPurpose>(
message: SignableMessage<T>,
private_key: &identity::PrivateKey,
) -> MessageSignature {
match message.algorithm {
SigningAlgorithm::Ed25519 => {
let plaintext = message.to_plaintext().unwrap();
let signature = private_key.sign(&plaintext);
MessageSignature::from(signature.to_bytes().as_ref())
}
SigningAlgorithm::Secp256k1 => {
unimplemented!()
}
}
}
@@ -1,18 +1,13 @@
use cosmwasm_std::{coins, Addr, Coin, Uint128};
use cw_multi_test::{App, AppBuilder, AppResponse, ContractWrapper, Executor};
use nym_contracts_common::signing::Nonce;
use nym_name_service_common::{
msg::{ExecuteMsg, InstantiateMsg, QueryMsg},
response::{ConfigResponse, PagedNamesListResponse},
signing_types::{construct_name_register_sign_payload, SignableNameRegisterMsg},
Address, NameDetails, NameId, NymName, RegisteredName,
Address, NameEntry, NameId, NymName,
};
use rand_chacha::ChaCha20Rng;
use serde::de::DeserializeOwned;
use crate::test_helpers::helpers::{get_app_attribute, test_rng};
use super::test_name::{SignedTestName, TestName};
use crate::test_helpers::helpers::get_app_attribute;
const DENOM: &str = "unym";
const ADDRESSES: &[&str] = &[
@@ -24,7 +19,6 @@ const WEALTHY_ADDRESSES: &[&str] = &["wealthy_owner_1", "wealthy_owner_2"];
pub struct TestSetup {
app: App,
addr: Addr,
rng: ChaCha20Rng,
}
impl Default for TestSetup {
@@ -50,8 +44,7 @@ impl TestSetup {
let code = ContractWrapper::new(crate::execute, crate::instantiate, crate::query);
let code_id = app.store_code(Box::new(code));
let addr = Self::instantiate(&mut app, code_id);
let rng = test_rng();
TestSetup { app, addr, rng }
TestSetup { app, addr }
}
fn instantiate(app: &mut App, code_id: u64) -> Addr {
@@ -83,7 +76,7 @@ impl TestSetup {
self.query(&QueryMsg::Config {})
}
pub fn query_id(&self, name_id: NameId) -> RegisteredName {
pub fn query_id(&self, name_id: NameId) -> NameEntry {
self.query(&QueryMsg::NameId { name_id })
}
@@ -99,48 +92,16 @@ impl TestSetup {
self.query(&QueryMsg::All { limit, start_after })
}
pub fn query_signing_nonce(&self, address: String) -> Nonce {
self.query(&QueryMsg::SigningNonce { address })
}
pub fn new_name(&mut self, name: &NymName, address: &Address) -> TestName {
TestName::new(&mut self.rng, name.clone(), address.clone())
}
pub fn payload_to_sign(
&mut self,
owner: &Addr,
deposit: &Coin,
name: &NameDetails,
) -> SignableNameRegisterMsg {
let nonce = self.query_signing_nonce(owner.to_string());
construct_name_register_sign_payload(nonce, owner.clone(), deposit.clone(), name.clone())
}
pub fn new_signed_name(
&mut self,
name: &NymName,
address: &Address,
owner: &Addr,
deposit: &Coin,
) -> SignedTestName {
let name = self.new_name(name, address);
let payload = self.payload_to_sign(owner, deposit, name.details());
name.sign(payload)
}
pub fn try_register(
&mut self,
name: &SignedTestName,
owner: &Addr,
name: NymName,
address: Address,
owner: Addr,
) -> anyhow::Result<AppResponse> {
self.app.execute_contract(
owner.clone(),
owner,
self.addr.clone(),
&ExecuteMsg::Register {
name: name.name.clone(),
owner_signature: name.owner_signature.clone(),
},
&ExecuteMsg::Register { name, address },
&[Coin {
denom: DENOM.to_string(),
amount: Uint128::new(100),
@@ -148,8 +109,8 @@ impl TestSetup {
)
}
pub fn register(&mut self, name: &SignedTestName, owner: &Addr) -> AppResponse {
let resp = self.try_register(name, owner).unwrap();
pub fn register(&mut self, name: NymName, address: Address, owner: Addr) -> AppResponse {
let resp = self.try_register(name, address, owner).unwrap();
assert_eq!(
get_app_attribute(&resp, "wasm-register", "action"),
"register"
@@ -157,19 +118,6 @@ impl TestSetup {
resp
}
// Convenience function for creating a new signed name, and regsitering it
pub fn sign_and_register(
&mut self,
name: &NymName,
address: &Address,
owner: &Addr,
deposit: &Coin,
) -> SignedTestName {
let signed_name = self.new_signed_name(name, address, owner, deposit);
self.register(&signed_name, owner);
signed_name
}
pub fn try_delete(&mut self, name_id: NameId, owner: Addr) -> anyhow::Result<AppResponse> {
self.app.execute_contract(
owner,
@@ -1,72 +0,0 @@
use cosmwasm_std::{
coin,
testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier},
DepsMut, MemoryStorage, OwnedDeps,
};
use nym_name_service_common::{
events::{NameEventType, NAME_ID},
msg::{ExecuteMsg, InstantiateMsg},
NameDetails, NameId, NymName,
};
use rand_chacha::rand_core::{CryptoRng, RngCore};
use super::helpers::{get_attribute, nyms};
pub fn instantiate_test_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {
deposit_required: coin(100, "unym"),
};
let env = mock_env();
let info = mock_info("creator", &[]);
let res = crate::instantiate(deps.as_mut(), env, info, msg).unwrap();
assert_eq!(res.messages.len(), 0);
deps
}
pub fn register_name<R>(
mut deps: DepsMut<'_>,
rng: &mut R,
name: &str,
nym_address: &str,
owner: &str,
) -> (NameId, NameDetails)
where
R: RngCore + CryptoRng,
{
let deposit = nyms(100);
let (name, owner_signature) = super::fixture::new_name_details_with_sign(
deps.branch(),
rng,
name,
nym_address,
owner,
deposit.clone(),
);
// Register
let msg = ExecuteMsg::Register {
name: name.clone(),
owner_signature,
};
let info = mock_info(owner, &[deposit]);
let res = crate::execute(deps, mock_env(), info, msg).unwrap();
let name_id: NameId = get_attribute(&res, &NameEventType::Register.to_string(), NAME_ID)
.parse()
.unwrap();
(name_id, name)
}
pub fn delete_name_id(deps: DepsMut<'_>, name_id: NameId, owner: &str) {
let msg = ExecuteMsg::DeleteId { name_id };
let info = mock_info(owner, &[]);
crate::execute(deps, mock_env(), info, msg).unwrap();
}
#[allow(unused)]
pub fn delete_name(deps: DepsMut<'_>, name: NymName, owner: &str) {
let msg = ExecuteMsg::DeleteName { name };
let info = mock_info(owner, &[]);
crate::execute(deps, mock_env(), info, msg).unwrap();
}
@@ -593,19 +593,10 @@ nyxd tx slashing unjail
### Upgrading your validator
Upgrading from `v0.26.0` -> `v0.31.1` process is fairly simple. Grab the v0.31.1 release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files:
- the new validator (`nyxd`) v0.31.1
- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`)
Before the upgrade height, copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`):
Then just swap in your new `nyxd` binary and restart once the halt height is reached.
Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process.
You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8).
Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. Luckily, the name of the wasmvm in v0.26.1 was `libwasmvm.so`, and the new name is `libwasmvm.x86_64.so`, so you can have it already sitting there without disrupting service.
#### Common reasons for your validator being jailed
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
+2 -6
View File
@@ -47,7 +47,7 @@ The example above involves ephemeral keys - if we want to create and then mainta
As seen in the example above, the `mixnet::MixnetClientBuilder::new()` function handles checking for keys in a storage location, loading them if present, or creating them and storing them if not, making client key management very simple.
### Manually handling storage
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_keys_and_config.rs`)
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_storage.rs`)
```rust,noplayground
{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_storage.rs}}
@@ -56,11 +56,7 @@ If you're integrating mixnet functionality into an existing app and want to inte
### Anonymous replies with SURBs
Both functions used to send messages through the mixnet (`send_str` and `send_bytes`) send a pre-determined number of SURBs along with their messages by default.
The number of SURBs is set [here](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/sdk/rust/nym-sdk/src/mixnet/client.rs#L35):
```rust,noplayground
{{#include ../../../../sdk/rust/nym-sdk/src/mixnet/client.rs:30}}
```
The number of SURBs is set [here](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/sdk/rust/nym-sdk/src/mixnet/client.rs#L36).
You can read more about how SURBs function under the hood [here](../architecture/traffic-flow.md#private-replies-using-surbs).
+1 -1
View File
@@ -1 +1 @@
18
16
+5
View File
@@ -22,6 +22,7 @@ pub(crate) mod init;
pub(crate) mod node_details;
pub(crate) mod run;
pub(crate) mod sign;
pub(crate) mod upgrade;
#[derive(Subcommand)]
pub(crate) enum Commands {
@@ -37,6 +38,9 @@ pub(crate) enum Commands {
/// Sign text to prove ownership of this mixnode
Sign(sign::Sign),
/// Try to upgrade the gateway
Upgrade(upgrade::Upgrade),
/// Generate shell completions
Completions(ArgShell),
@@ -67,6 +71,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
Commands::NodeDetails(m) => node_details::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::Sign(m) => sign::execute(m)?,
Commands::Upgrade(m) => upgrade::execute(&m).await,
Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
}
+154
View File
@@ -0,0 +1,154 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::Config;
use clap::Args;
use nym_bin_common::version_checker::Version;
use std::fmt::Display;
use std::process;
#[derive(Args, Clone)]
pub struct Upgrade {
/// Id of the nym-gateway we want to upgrade
#[clap(long)]
id: String,
}
#[allow(dead_code)]
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
print_failed_upgrade(from_version, to_version);
process::exit(1)
}
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!(
"\n==================\nTrying to upgrade gateway from {} to {} ...",
from, to
);
}
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!(
"Upgrade from {} to {} failed!\n==================\n",
from, to
);
}
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!(
"Upgrade from {} to {} was successful!\n==================\n",
from, to
);
}
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!(
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
config_version, package_version
);
process::exit(1)
}
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
process::exit(1)
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(&config.gateway.version).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {}. This is not supported!",
version
);
process::exit(1)
}
version
}
fn parse_package_version() -> Version {
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade to a non-released version {}. This is not supported!",
version
);
process::exit(1)
}
version
}
fn minor_0_12_upgrade(
config: Config,
_args: &Upgrade,
config_version: &Version,
package_version: &Version,
) -> Config {
let to_version = if package_version.major == 0 && package_version.minor == 12 {
package_version.clone()
} else {
Version::new(0, 12, 0)
};
print_start_upgrade(config_version, &to_version);
let upgraded_config = config.with_custom_version(to_version.to_string());
upgraded_config
.save_to_default_location()
.unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
print_successful_upgrade(config_version, to_version);
upgraded_config
}
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
loop {
let config_version = parse_config_version(&config);
if config_version == package_version {
eprintln!("You're using the most recent version!");
return;
}
config = match config_version.major {
0 => match config_version.minor {
9 | 10 => outdated_upgrade(&config_version, &package_version),
11 => minor_0_12_upgrade(config, args, &config_version, &package_version),
_ => unsupported_upgrade(&config_version, &package_version),
},
_ => unsupported_upgrade(&config_version, &package_version),
}
}
}
pub async fn execute(args: &Upgrade) {
let package_version = parse_package_version();
let existing_config = Config::read_from_default_path(&args.id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
if existing_config.gateway.version.is_empty() {
eprintln!("the existing configuration file does not seem to contain version number.");
process::exit(1);
}
do_upgrade(existing_config, args, package_version)
}
+5
View File
@@ -159,6 +159,11 @@ impl Config {
self
}
pub fn with_custom_version<S: Into<String>>(mut self, version: S) -> Self {
self.gateway.version = version.into();
self
}
pub fn get_statistics_service_url(&self) -> Url {
self.gateway.statistics_service_url.clone()
}
+8 -2
View File
@@ -1,4 +1,10 @@
{
"version": "0.0.0",
"useWorkspaces": true
"packages": [
"ts-packages/*",
"nym-wallet",
"nym-connect/**",
"sdk/typescript/examples/docs",
"sdk/typescript/packages/**"
],
"version": "0.0.0"
}
+5
View File
@@ -20,6 +20,7 @@ mod init;
mod node_details;
mod run;
mod sign;
mod upgrade;
#[derive(Subcommand)]
pub(crate) enum Commands {
@@ -35,6 +36,9 @@ pub(crate) enum Commands {
/// Sign text to prove ownership of this mixnode
Sign(sign::Sign),
/// Try to upgrade the mixnode
Upgrade(upgrade::Upgrade),
/// Show details of this mixnode
NodeDetails(node_details::NodeDetails),
@@ -63,6 +67,7 @@ pub(crate) async fn execute(args: Cli) -> anyhow::Result<()> {
Commands::Init(m) => init::execute(&m),
Commands::Run(m) => run::execute(&m).await?,
Commands::Sign(m) => sign::execute(&m)?,
Commands::Upgrade(m) => upgrade::execute(&m)?,
Commands::NodeDetails(m) => node_details::execute(&m)?,
Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
+144
View File
@@ -0,0 +1,144 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_upgrade_v1_1_21_config;
use crate::config::Config;
use clap::Args;
use nym_bin_common::version_checker::Version;
use std::fmt::Display;
use std::process;
#[derive(Args)]
pub(crate) struct Upgrade {
/// Id of the nym-mixnode we want to upgrade
#[clap(long)]
id: String,
}
#[allow(dead_code)]
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
print_failed_upgrade(from_version, to_version);
process::exit(1)
}
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!("\n==================\nTrying to upgrade mixnode from {from} to {to} ...");
}
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!("Upgrade from {from} to {to} failed!\n==================\n");
}
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!("Upgrade from {from} to {to} was successful!\n==================\n");
}
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!(
"Cannot perform upgrade from {config_version} to {package_version}. Your version is too old to perform the upgrade.!"
);
process::exit(1)
}
fn unsupported_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {config_version} to {package_version}. Please let the developers know about this issue if you expected it to work!");
process::exit(1)
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(&config.mixnode.version).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {version}. This is not supported!"
);
process::exit(1)
}
version
}
fn parse_package_version() -> Version {
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
process::exit(1)
}
version
}
fn minor_0_12_upgrade(
config: Config,
_args: &Upgrade,
config_version: &Version,
package_version: &Version,
) -> Config {
let to_version = if package_version.major == 0 && package_version.minor == 12 {
package_version.clone()
} else {
Version::new(0, 12, 0)
};
print_start_upgrade(config_version, &to_version);
let upgraded_config = config.with_custom_version(to_version.to_string());
upgraded_config
.save_to_default_location()
.unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
print_successful_upgrade(config_version, to_version);
upgraded_config
}
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
loop {
let config_version = parse_config_version(&config);
if config_version == package_version {
println!("You're using the most recent version!");
return;
}
config = match config_version.major {
0 => match config_version.minor {
9 | 10 => outdated_upgrade(&config_version, &package_version),
11 => minor_0_12_upgrade(config, args, &config_version, &package_version),
_ => unsupported_upgrade(&config_version, &package_version),
},
_ => unsupported_upgrade(&config_version, &package_version),
}
}
}
pub(crate) fn execute(args: &Upgrade) -> anyhow::Result<()> {
try_upgrade_v1_1_21_config(&args.id)?;
let package_version = parse_package_version();
let existing_config = Config::read_from_default_path(&args.id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
if existing_config.mixnode.version.is_empty() {
eprintln!("the existing configuration file does not seem to contain version number.");
process::exit(1);
}
do_upgrade(existing_config, args, package_version);
Ok(())
}
+5
View File
@@ -147,6 +147,11 @@ impl Config {
self
}
pub fn with_custom_version<S: Into<String>>(mut self, version: S) -> Self {
self.mixnode.version = version.into();
self
}
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.mixnode.nym_api_urls.clone()
}
+2 -2
View File
@@ -6,7 +6,7 @@ use nym_mixnet_contract_common::{
families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeDetails,
RewardingParams,
};
use nym_name_service_common::RegisteredName;
use nym_name_service_common::NameEntry;
use nym_service_provider_directory_common::Service;
use std::collections::HashSet;
@@ -26,7 +26,7 @@ pub(crate) struct ValidatorCacheData {
pub(crate) mix_to_family: Cache<Vec<(IdentityKey, FamilyHead)>>,
pub(crate) service_providers: Cache<Vec<Service>>,
pub(crate) registered_names: Cache<Vec<RegisteredName>>,
pub(crate) registered_names: Cache<Vec<NameEntry>>,
}
impl ValidatorCacheData {
+3 -3
View File
@@ -5,7 +5,7 @@ use nym_mixnet_contract_common::{
families::FamilyHead, GatewayBond, IdentityKey, Interval, MixId, MixNodeBond, MixNodeDetails,
RewardingParams,
};
use nym_name_service_common::RegisteredName;
use nym_name_service_common::NameEntry;
use nym_service_provider_directory_common::Service;
use rocket::fairing::AdHoc;
use std::{
@@ -53,7 +53,7 @@ impl NymContractCache {
current_interval: Interval,
mix_to_family: Vec<(IdentityKey, FamilyHead)>,
services: Option<Vec<Service>>,
names: Option<Vec<RegisteredName>>,
names: Option<Vec<NameEntry>>,
) {
match time::timeout(Duration::from_millis(100), self.inner.write()).await {
Ok(mut cache) => {
@@ -303,7 +303,7 @@ impl NymContractCache {
}
}
pub(crate) async fn names(&self) -> Cache<Vec<RegisteredName>> {
pub(crate) async fn names(&self) -> Cache<Vec<NameEntry>> {
match time::timeout(Duration::from_millis(100), self.inner.read()).await {
Ok(cache) => cache.registered_names.clone(),
Err(err) => {
+1 -1
View File
@@ -1 +1 @@
18
14
-4
View File
@@ -3564,12 +3564,8 @@ name = "nym-name-service-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"cw-controllers",
"cw-utils",
"nym-contracts-common",
"schemars",
"serde",
"thiserror",
]
[[package]]
+13 -17
View File
@@ -30,7 +30,19 @@ pub enum Socks5ExitStatusMessage {
Failed(Box<dyn std::error::Error + Send>),
}
fn override_config_from_env(config: &mut Config) {
/// The main SOCKS5 client task. It loads the configuration from file determined by the `id`.
pub async fn start_nym_socks5_client(
id: &str,
) -> Result<(
Socks5ControlMessageSender,
nym_task::StatusReceiver,
ExitStatusReceiver,
GatewayEndpointConfig,
)> {
log::info!("Loading config from file: {id}");
let mut config = Config::read_from_default_path(id)
.tap_err(|_| log::warn!("Failed to load configuration file"))?;
// Disable both the loop cover traffic that runs in the background as well as the Poisson
// process that injects cover traffic into the traffic stream.
if std::env::var("NYM_CONNECT_DISABLE_COVER").is_ok() {
@@ -50,22 +62,6 @@ fn override_config_from_env(config: &mut Config) {
log::warn!("Disabling per-hop delay");
config.core.base.set_no_per_hop_delays();
}
}
/// The main SOCKS5 client task. It loads the configuration from file determined by the `id`.
pub async fn start_nym_socks5_client(
id: &str,
) -> Result<(
Socks5ControlMessageSender,
nym_task::StatusReceiver,
ExitStatusReceiver,
GatewayEndpointConfig,
)> {
log::info!("Loading config from file: {id}");
let mut config = Config::read_from_default_path(id)
.tap_err(|_| log::warn!("Failed to load configuration file"))?;
override_config_from_env(&mut config);
log::trace!("Configuration used: {:#?}", config);
+1 -2
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { Apps, HelpOutline, Settings, BugReport } from '@mui/icons-material';
import { Apps, HelpOutline, Settings } from '@mui/icons-material';
import { Stack, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import { AppVersion } from 'src/components/AppVersion';
@@ -7,7 +7,6 @@ import { AppVersion } from 'src/components/AppVersion';
const menuSchema = [
{ title: 'Supported apps', icon: Apps, path: 'apps' },
{ title: 'How to connect guide', icon: HelpOutline, path: 'guide' },
{ title: 'Please help us improve the app', icon: BugReport, path: 'monitoring' },
{ title: 'Settings', icon: Settings, path: 'settings' },
];
@@ -34,6 +34,10 @@ export const MonitoringSettings = () => {
occur or if the app crashes, it will automatically send a report. Also it tracks various performance
metrics. We use sentry.io service to handle this.
</FormHelperText>
<FormHelperText sx={{ m: 0, mb: 2 }}>
Note: A report can include your external IP, this can be useful to catch issues related to IP location.
All recorded data is used by Nym developers and for app development purposes only.
</FormHelperText>
</FormControl>
<Stack direction="row" gap={1} alignItems="center">
<WarningIcon color="warning" fontSize="small" />
@@ -7,6 +7,7 @@ import { toggleLogViewer } from 'src/utils';
const menuSchema = [
{ title: 'Select your gateway', path: 'gateway' },
{ title: 'Select a service provider', path: 'service-provider' },
{ title: 'Help improve the app', path: 'monitoring' },
];
export const SettingsMenu = () => (
+1 -1
View File
@@ -25,11 +25,11 @@ export const AppRoutes = () => {
<Route index element={<Menu />} />
<Route path="apps" element={<CompatibleApps />} />
<Route path="guide" element={<HelpGuide />} />
<Route path="monitoring" element={<MonitoringSettings />} />
<Route path="settings">
<Route index element={<SettingsMenu />} />
<Route path="gateway" element={<GatewaySettings />} />
<Route path="service-provider" element={<ServiceProviderSettings />} />
<Route path="monitoring" element={<MonitoringSettings />} />
</Route>
</Route>
</RoutesContainer>
-2
View File
@@ -43,8 +43,6 @@ async function initSentry() {
getVersion().then((version) => {
Sentry.setTag('app_version', version);
});
Sentry.setUser({ id: 'nym', ip_address: undefined });
}
export default initSentry;
+1 -1
View File
@@ -1 +1 @@
18
14
+1 -1
View File
@@ -99,6 +99,7 @@ android {
}
dependencies {
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.activity:activity-compose:1.7.2'
@@ -123,5 +124,4 @@ dependencies {
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'
implementation 'com.github.kittinunf.fuel:fuel:3.0.0-alpha1'
implementation 'io.sentry:sentry-android:6.24.0'
}
@@ -2,8 +2,6 @@ package net.nymtech.nyms5
import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
@@ -11,15 +9,11 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.work.Configuration
import androidx.work.DelegatingWorkerFactory
import io.sentry.Scope
import io.sentry.Sentry
import io.sentry.android.core.SentryAndroid
import io.sentry.protocol.User
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
val monitoringKey = booleanPreferencesKey("monitoring")
@@ -46,34 +40,11 @@ class App : Application(), Configuration.Provider {
options.dsn =
"https://6872f5818bc147ef9c0fce114fcaac8a@o967446.ingest.sentry.io/4505306218102784"
options.enableAllAutoBreadcrumbs(true)
options.isEnableUserInteractionTracing = true
options.isEnableUserInteractionBreadcrumbs = true
// TODO should be adjusted in production env
options.sampleRate = 1.0
options.tracesSampleRate = 1.0
options.profilesSampleRate = 1.0
}
Sentry.configureScope { scope: Scope ->
val packageManager = applicationContext.packageManager
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(
packageName,
PackageManager.PackageInfoFlags.of(0)
)
} else {
packageManager.getPackageInfo(packageName, 0)
}
scope.setTag("app_version", packageInfo.versionName)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
scope.setTag("app_version_code", packageInfo.longVersionCode.toString())
}
}
val user = User()
user.id = "nym"
Sentry.setUser(user)
}
}
}
@@ -50,7 +50,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
@@ -250,7 +249,7 @@ fun S5ClientSwitch(
Spacer(modifier = modifier.width(14.dp))
Switch(checked = connected, enabled = !loading, onCheckedChange = {
onSwitch(!connected)
}, modifier = Modifier.testTag("switch_connect"))
})
}
if (connected && !loading) {
Column(modifier = modifier.padding(16.dp)) {
@@ -333,10 +332,12 @@ fun Monitoring(
tint = Color.Yellow
)
Spacer(modifier = modifier.width(16.dp))
Text(stringResource(R.string.monitoring_desc_2), color = Color.Yellow)
Text(stringResource(R.string.monitoring_desc_3), color = Color.Yellow)
}
Spacer(modifier = modifier.height(18.dp))
Text(stringResource(R.string.monitoring_desc_1))
Spacer(modifier = modifier.height(18.dp))
Text(stringResource(R.string.monitoring_desc_2))
}
}
@@ -1,7 +1,6 @@
package net.nymtech.nyms5
import android.util.Log
import io.sentry.Sentry
const val nymNativeLib = "nym_socks5_listener"
@@ -28,7 +27,6 @@ class NymProxy {
startClient(serviceProvider, onStartCbObj, onStopCbObj)
} catch (e: Throwable) {
Log.e(tag, "$nymNativeLib:startClient internal error: $e")
Sentry.captureException(e)
}
}
@@ -38,7 +36,6 @@ class NymProxy {
stopClient()
} catch (e: Throwable) {
Log.e(tag, "$nymNativeLib:stopClient internal error: $e")
Sentry.captureException(e)
}
}
@@ -53,7 +50,6 @@ class NymProxy {
}
} catch (e: Throwable) {
Log.e(tag, "$nymNativeLib:getClientState internal error: $e")
Sentry.captureException(e)
}
return State.UNINITIALIZED
}

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