Compare commits

..

1 Commits

Author SHA1 Message Date
Tommy Verrall b6617eb34c Update PULL_REQUEST_TEMPLATE.md 2024-06-11 12:11:52 +02:00
583 changed files with 37848 additions and 3060 deletions
+43
View File
@@ -0,0 +1,43 @@
# Description
<!-- Please include a summary of the change and which issue is fixed. Also include relevant motivation and context. List any dependencies that are required for this change. -->
Fixes # (issue)
## Type of Change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## How Has This Been Tested?
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
- [ ] Test A
- [ ] Test B
**Test Configuration**:
* Component:
* Chain:
* Binaries:
* SDK:
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I have added a changelog entry to `CHANGELOG.md`
- [ ] I have checked my code and corrected any misspellings
## Additional Notes
<!-- Any other notes (e.g. discussions, concerns, etc) you want to include -->
@@ -104,9 +104,12 @@ jobs:
name: nym-binaries-artifacts
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
@@ -121,9 +124,12 @@ jobs:
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
run: |
cp target/release/nym-client $OUTPUT_DIR
cp target/release/nym-gateway $OUTPUT_DIR
cp target/release/nym-mixnode $OUTPUT_DIR
cp target/release/nym-socks5-client $OUTPUT_DIR
cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nymvisor $OUTPUT_DIR
cp target/release/nym-node $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
+2
View File
@@ -6,6 +6,7 @@ on:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'ephemera/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
@@ -23,6 +24,7 @@ on:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'ephemera/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
@@ -0,0 +1,65 @@
name: ci-nym-connect-desktop-rust
on:
pull_request:
paths:
- "nym-connect/desktop/src-tauri/**"
- "nym-connect/desktop/src-tauri/Cargo.toml"
- "clients/client-core/**"
- "clients/socks5/**"
- "common/**"
- "gateway/gateway-requests/**"
- "contracts/vesting/**"
- "nym-api/nym-api-requests/**"
jobs:
build:
runs-on: [self-hosted, custom-linux]
env:
CARGO_TERM_COLOR: always
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev
continue-on-error: true
- name: Check out repository code
uses: actions/checkout@v2
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-connect/desktop/Cargo.toml --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace --all-features
- name: Run clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace --all-features -- -D warnings
@@ -0,0 +1,72 @@
name: ci-nym-connect-desktop
on:
pull_request:
paths:
- 'nym-connect/desktop/**'
defaults:
run:
working-directory: nym-connect/desktop
jobs:
build:
runs-on: custom-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install 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: Install project dependencies
run: cd ../.. && yarn --network-timeout 100000
- name: Install app dependencies
run: yarn
continue-on-error: true
- name: Set environment from the example
run: cp .env.sample .env
- run: yarn storybook:build
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "nym-connect/desktop/storybook-static/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/nym-connect-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: nym-connect
NYM_PROJECT_NAME: "nym-connect"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "nym-connect-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -0,0 +1,92 @@
name: nightly-nym-connect-desktop-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
MANIFEST_PATH: --manifest-path nym-connect/desktop/Cargo.toml
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
if: matrix.os == 'ubuntu-20.04'
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: ${{ env.MANIFEST_PATH }} --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: ${{ env.MANIFEST_PATH }} --release --workspace
- name: Unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: ${{ env.MANIFEST_PATH }} --workspace
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "nym-connect-desktop-nightly-build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-27
View File
@@ -1,27 +0,0 @@
name: pr-validation
on:
pull_request:
branches:
- develop
- 'release/**'
types:
- labeled
- unlabeled
- opened
- reopened
- synchronize
- edited
- milestoned
- demilestoned
env:
LABELS: ${{ join( github.event.pull_request.labels.*.name, ' ' ) }}
jobs:
check-milestone:
name: Check Milestone
runs-on: ubuntu-latest
steps:
- if: github.event.pull_request.milestone == null && contains( env.LABELS, 'no-milestone' ) == false
run: exit 1
@@ -27,17 +27,23 @@ jobs:
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 }}
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
nymnode_hash: ${{ steps.binary-hashes.outputs.nymnode_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 }}
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
nymnode_version: ${{ steps.binary-versions.outputs.nymnode_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
@@ -69,9 +75,12 @@ jobs:
path: |
target/release/explorer-api
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
@@ -85,9 +94,12 @@ jobs:
files: |
target/release/explorer-api
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
@@ -0,0 +1,122 @@
name: publish-nym-connect-macos
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect/desktop
jobs:
publish-tauri:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
platform: [macos-12-large]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_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
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: wasm32-unknown-unknown
- name: Install wasm-pack
run: |
export WASM_PACK_VERSION="v0.12.1"
curl -LO https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
tar xvzf wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz -C $HOME/.cargo/bin --strip-components=1
rm wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
- name: Install the Apple developer certificate for code signing
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file
uses: timheuer/base64-to-file@v1.2
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies and build it
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn && yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect_1.0.0_x64.dmg
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1*_x64.dmg
retention-days: 30
- name: Clean up keychain
if: ${{ always() }}
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release
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*
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
secrets: inherit
@@ -0,0 +1,89 @@
name: publish-nym-connect-ubuntu
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect/desktop
jobs:
publish-tauri:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
platform: [custom-ubuntu-20.04]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_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: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
continue-on-error: true
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies
run: yarn
- name: Create env file
uses: timheuer/base64-to-file@v1.2
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Build app
run: yarn build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect.AppImage.tar.gz
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1*_amd64.AppImage
retention-days: 30
- id: create-release
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*
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
secrets: inherit
@@ -0,0 +1,108 @@
name: publish-nym-connect-win10
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect/desktop
jobs:
publish-tauri:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
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].created_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
working-directory: .
run: |
cd ..
del /s /q /A:H nym
rmdir /s /q nym
- uses: actions/checkout@v3
- name: Import signing certificate
env:
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Create env file
uses: timheuer/base64-to-file@v1.2
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies
shell: bash
run: yarn --network-timeout 100000
- name: Build and sign it
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect_1.0.0_x64_en-US.msi
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1*_x64_en-US.msi
retention-days: 30
- id: create-release
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*
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
secrets: inherit
@@ -0,0 +1,29 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -0,0 +1,16 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,16 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View storybook:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
-72
View File
@@ -4,78 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.7-doubledecker] (2024-07-04)
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
- Bump braces from 3.0.2 to 3.0.3 in /wasm/mix-fetch/internal-dev ([#4672])
- add expiry returned on import ([#4670])
- [bugfix] missing rustls feature ([#4666])
- Bump ws from 8.13.0 to 8.17.1 in /wasm/client/internal-dev-node ([#4665])
- Bump braces from 3.0.2 to 3.0.3 in /clients/native/examples/js-examples/websocket ([#4663])
- Bump ws from 8.14.2 to 8.17.1 in /sdk/typescript/packages/nodejs-client ([#4662])
- Update setup.md ([#4661])
- New clippy lints ([#4660])
- Bump braces from 3.0.2 to 3.0.3 in /nym-api/tests ([#4659])
- Bump braces from 3.0.2 to 3.0.3 in /docker/typescript_client/upload_contract ([#4658])
- Update vps-setup.md ([#4656])
- Update configuration.md ([#4655])
- Remove old PR template ([#4639])
[#4686]: https://github.com/nymtech/nym/pull/4686
[#4672]: https://github.com/nymtech/nym/pull/4672
[#4670]: https://github.com/nymtech/nym/pull/4670
[#4666]: https://github.com/nymtech/nym/pull/4666
[#4665]: https://github.com/nymtech/nym/pull/4665
[#4663]: https://github.com/nymtech/nym/pull/4663
[#4662]: https://github.com/nymtech/nym/pull/4662
[#4661]: https://github.com/nymtech/nym/pull/4661
[#4660]: https://github.com/nymtech/nym/pull/4660
[#4659]: https://github.com/nymtech/nym/pull/4659
[#4658]: https://github.com/nymtech/nym/pull/4658
[#4656]: https://github.com/nymtech/nym/pull/4656
[#4655]: https://github.com/nymtech/nym/pull/4655
[#4639]: https://github.com/nymtech/nym/pull/4639
## [2024.6-chomp] (2024-06-25)
- Remove additional code as part of Ephemera Purge and SP and contracts ([#4650])
- bugfix: make sure nym-api can handle non-cw2 (or without detailed build info) compliant contracts ([#4648])
- introduced a flag to accept toc and exposed it via self-described API ([#4647])
- bugfix: make sure to return an error on invalid public ip ([#4646])
- Add ci check for PR having an assigned milestone ([#4644])
- Removed ephemera code ([#4642])
- Remove stale peers ([#4640])
- Add generic wg private network routing ([#4636])
- Feature/new node endpoints ([#4635])
- standarised ContractBuildInformation and added it to all contracts ([#4631])
- validate nym-node public ips on startup ([#4630])
- Bump defguard wg ([#4625])
- Fix cargo warnings ([#4624])
- Update kernel peers on peer modification ([#4622])
- Handle v6 and v7 requests in the IPR, but reply with v6 ([#4620])
- fix typo ([#4619])
- Update crypto and rand crates ([#4607])
- Purge name service and service provider directory contracts ([#4603])
[#4650]: https://github.com/nymtech/nym/pull/4650
[#4648]: https://github.com/nymtech/nym/pull/4648
[#4647]: https://github.com/nymtech/nym/pull/4647
[#4646]: https://github.com/nymtech/nym/pull/4646
[#4644]: https://github.com/nymtech/nym/pull/4644
[#4642]: https://github.com/nymtech/nym/pull/4642
[#4640]: https://github.com/nymtech/nym/pull/4640
[#4636]: https://github.com/nymtech/nym/pull/4636
[#4635]: https://github.com/nymtech/nym/pull/4635
[#4631]: https://github.com/nymtech/nym/pull/4631
[#4630]: https://github.com/nymtech/nym/pull/4630
[#4625]: https://github.com/nymtech/nym/pull/4625
[#4624]: https://github.com/nymtech/nym/pull/4624
[#4622]: https://github.com/nymtech/nym/pull/4622
[#4620]: https://github.com/nymtech/nym/pull/4620
[#4619]: https://github.com/nymtech/nym/pull/4619
[#4607]: https://github.com/nymtech/nym/pull/4607
[#4603]: https://github.com/nymtech/nym/pull/4603
## [2024.5-ragusa] (2024-05-22)
- Feature/nym node api location ([#4605])
Generated
+34 -17
View File
@@ -526,6 +526,8 @@ dependencies = [
"bs58 0.5.1",
"hmac",
"k256",
"once_cell",
"pbkdf2",
"rand_core 0.6.4",
"ripemd",
"sha2 0.10.8",
@@ -2093,7 +2095,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "explorer-api"
version = "1.1.36"
version = "1.1.34"
dependencies = [
"chrono",
"clap 4.5.4",
@@ -2202,6 +2204,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
dependencies = [
"bitvec",
"rand_core 0.6.4",
"subtle 2.5.0",
]
@@ -3858,7 +3861,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.40"
version = "1.1.38"
dependencies = [
"anyhow",
"async-trait",
@@ -3940,7 +3943,6 @@ dependencies = [
"nym-crypto",
"nym-mixnet-contract-common",
"nym-node-requests",
"rocket",
"schemars",
"serde",
"serde_json",
@@ -4018,7 +4020,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.38"
version = "1.1.36"
dependencies = [
"anyhow",
"base64 0.13.1",
@@ -4097,7 +4099,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.37"
version = "1.1.35"
dependencies = [
"bs58 0.5.1",
"clap 4.5.4",
@@ -4337,12 +4339,10 @@ dependencies = [
"bs58 0.5.1",
"cosmwasm-schema",
"cosmwasm-std",
"cw-storage-plus",
"schemars",
"serde",
"serde_json",
"thiserror",
"vergen",
]
[[package]]
@@ -4459,6 +4459,16 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-ephemera-common"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cw-utils",
"nym-contracts-common",
]
[[package]]
name = "nym-execute"
version = "0.1.0"
@@ -4910,7 +4920,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.38"
version = "1.1.36"
dependencies = [
"addr",
"anyhow",
@@ -4979,7 +4989,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.1.4"
version = "1.1.2"
dependencies = [
"anyhow",
"bip39",
@@ -5241,7 +5251,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.37"
version = "1.1.35"
dependencies = [
"bs58 0.5.1",
"clap 4.5.4",
@@ -5640,6 +5650,7 @@ dependencies = [
"nym-coconut-dkg-common",
"nym-config",
"nym-contracts-common",
"nym-ephemera-common",
"nym-group-contract-common",
"nym-http-api-client",
"nym-mixnet-contract-common",
@@ -5741,7 +5752,6 @@ dependencies = [
"nym-task",
"nym-wireguard-types",
"tokio",
"tokio-stream",
"x25519-dalek",
]
@@ -5767,7 +5777,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.3"
version = "0.1.1"
dependencies = [
"anyhow",
"bytes",
@@ -6079,6 +6089,16 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest 0.10.7",
"hmac",
]
[[package]]
name = "pear"
version = "0.2.9"
@@ -9215,14 +9235,11 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vergen"
version = "8.3.1"
version = "8.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525"
checksum = "1290fd64cc4e7d3c9b07d7f333ce0ce0007253e32870e632624835cc80b83939"
dependencies = [
"anyhow",
"cargo_metadata",
"cfg-if",
"regex",
"rustc_version 0.4.0",
"rustversion",
"time",
+14 -13
View File
@@ -35,6 +35,7 @@ members = [
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
# "common/cosmwasm-smart-contracts/ephemera",
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
@@ -116,7 +117,7 @@ members = [
"tools/nymvisor",
"tools/ts-rs-cli",
"wasm/client",
# "wasm/full-nym-wasm", # If we uncomment this again, remember to also uncomment the profile settings below
# "wasm/full-nym-wasm",
"wasm/mix-fetch",
"wasm/node-tester",
"wasm/zknym-lib",
@@ -140,6 +141,9 @@ exclude = [
"explorer",
"contracts",
"nym-wallet",
"nym-connect/mobile/src-tauri",
"nym-connect/desktop",
"nym-vpn/ui/src-tauri",
"cpu-cycles",
"sdk/ffi/cpp",
]
@@ -286,7 +290,7 @@ tungstenite = { version = "0.20.1", default-features = false }
url = "2.4"
utoipa = "4.2.0"
utoipa-swagger-ui = "6.0.0"
vergen = { version = "=8.3.1", default-features = false }
vergen = { version = "=8.2.6", default-features = false }
walkdir = "2"
wasm-bindgen-test = "0.3.36"
zeroize = "1.6.0"
@@ -296,9 +300,9 @@ prometheus = { version = "0.13.0" }
# coconut/DKG related
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "feature/gt-serialization-0.8.0" }
group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.0", default-features = false }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "feature/gt-serialization-0.8.0" }
group = "0.13.0"
ff = "0.13.0"
# cosmwasm-related
cosmwasm-derive = "=1.4.3"
@@ -317,14 +321,14 @@ cw4 = { version = "=1.1.2" }
cw-controllers = { version = "=1.1.0" }
# cosmrs-related
bip32 = { version = "0.5.1", default-features = false }
bip32 = "0.5.1"
# temporarily using a fork again (yay.) because we need staking and slashing support
cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" }
#cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" } # unfortuntely we need a fork by yours truly to get the staking support
tendermint = "0.34" # same version as used by cosmrs
tendermint-rpc = "0.34" # same version as used by cosmrs
prost = { version = "0.12", default-features = false }
prost = "0.12"
# wasm-related dependencies
gloo-utils = "0.2.0"
@@ -352,12 +356,9 @@ opt-level = 'z'
# lto = true
opt-level = 'z'
# Commented out since the crate is also commented out from the inclusion in the
# workspace above. We should uncomment this if we re-include it in the
# workspace
#[profile.release.package.nym-wasm-sdk]
## lto = true
#opt-level = 'z'
[profile.release.package.nym-wasm-sdk]
# lto = true
opt-level = 'z'
[profile.release.package.mix-fetch-wasm]
# lto = true
+1
View File
@@ -92,6 +92,7 @@ endef
$(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown,RUSTFLAGS='-C link-arg=-s'))
$(eval $(call add_cargo_workspace,wallet,nym-wallet))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
# -----------------------------------------------------------------------------
# SDK
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.37"
version = "1.1.35"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+236 -78
View File
@@ -744,18 +744,6 @@
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/browserslist": {
"version": "4.20.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz",
@@ -874,6 +862,51 @@
"fsevents": "~2.3.2"
}
},
"node_modules/chokidar/node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/chokidar/node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/chokidar/node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/chokidar/node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/chrome-trace-event": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
@@ -1560,6 +1593,39 @@
"node": ">=8.6.0"
}
},
"node_modules/fast-glob/node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fast-glob/node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fast-glob/node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/fast-glob/node_modules/micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -1573,6 +1639,18 @@
"node": ">=8.6"
}
},
"node_modules/fast-glob/node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -1605,18 +1683,6 @@
"node": ">=0.8.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
@@ -2071,6 +2137,39 @@
}
}
},
"node_modules/http-proxy-middleware/node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/http-proxy-middleware/node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/http-proxy-middleware/node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/http-proxy-middleware/node_modules/micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -2084,6 +2183,18 @@
"node": ">=8.6"
}
},
"node_modules/http-proxy-middleware/node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -2250,15 +2361,6 @@
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
@@ -3751,18 +3853,6 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"dev": true
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -5123,15 +5213,6 @@
"concat-map": "0.0.1"
}
},
"braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.1.1"
}
},
"browserslist": {
"version": "4.20.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz",
@@ -5202,6 +5283,41 @@
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"dependencies": {
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"chrome-trace-event": {
@@ -5736,6 +5852,30 @@
"micromatch": "^4.0.4"
},
"dependencies": {
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -5745,6 +5885,15 @@
"braces": "^3.0.1",
"picomatch": "^2.2.3"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
@@ -5777,15 +5926,6 @@
"websocket-driver": ">=0.5.1"
}
},
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
@@ -6107,6 +6247,30 @@
"micromatch": "^4.0.2"
},
"dependencies": {
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -6116,6 +6280,15 @@
"braces": "^3.0.1",
"picomatch": "^2.2.3"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
@@ -6234,12 +6407,6 @@
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
@@ -7357,15 +7524,6 @@
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-1
View File
@@ -73,7 +73,6 @@ impl From<Init> for OverrideConfig {
fn from(init_config: Init) -> Self {
OverrideConfig {
nym_apis: init_config.common_args.nym_apis,
fronting_domains: init_config.common_args.fronting_domains,
disable_socket: init_config.disable_socket,
port: init_config.port,
host: init_config.host,
-5
View File
@@ -97,7 +97,6 @@ pub(crate) enum Commands {
// Configuration that can be overridden.
pub(crate) struct OverrideConfig {
nym_apis: Option<Vec<url::Url>>,
fronting_domains: Option<Vec<url::Url>>,
disable_socket: Option<bool>,
port: Option<u16>,
host: Option<IpAddr>,
@@ -134,10 +133,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_optional(Config::with_port, args.port)
.with_optional(Config::with_host, args.host)
.with_optional_ext(
BaseClientConfig::with_fronting_domains,
args.fronting_domains,
)
.with_optional_custom_env_ext(
BaseClientConfig::with_custom_nym_apis,
args.nym_apis,
-1
View File
@@ -36,7 +36,6 @@ impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self {
OverrideConfig {
nym_apis: run_config.common_args.nym_apis,
fronting_domains: run_config.common_args.fronting_domains,
disable_socket: run_config.disable_socket,
port: run_config.port,
host: run_config.host,
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.37"
version = "1.1.35"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
@@ -24,11 +24,6 @@ const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20)
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
// the same values as our current (10.06.24) blacklist
const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50;
const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50;
const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
@@ -117,11 +112,6 @@ impl Config {
self
}
pub fn with_fronting_domains(mut self, fronting_domains: Vec<Url>) -> Self {
self.client.fronting_domains = Some(fronting_domains);
self
}
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
self.client.nym_api_urls = nym_api_urls;
}
@@ -294,10 +284,6 @@ impl Config {
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.client.nym_api_urls.clone()
}
pub fn get_fronting_domains(&self) -> Option<Vec<Url>> {
self.client.fronting_domains.clone()
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
@@ -323,9 +309,6 @@ pub struct Client {
/// Addresses to APIs running on validator from which the client gets the view of the network.
#[serde(alias = "validator_api_urls")]
pub nym_api_urls: Vec<Url>,
/// Domain to use for domain fronting censorship circumvention
pub fronting_domains: Option<Vec<Url>>,
}
impl Client {
@@ -352,7 +335,6 @@ impl Client {
disabled_credentials_mode: true,
nyxd_urls,
nym_api_urls,
fronting_domains: None,
}
}
@@ -362,7 +344,6 @@ impl Client {
disabled_credentials_mode: bool,
nyxd_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
fronting_domains: Option<Vec<Url>>,
) -> Self {
Client {
version: version.into(),
@@ -370,7 +351,6 @@ impl Client {
disabled_credentials_mode,
nyxd_urls,
nym_api_urls,
fronting_domains,
}
}
}
@@ -536,14 +516,6 @@ pub struct Topology {
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructure,
/// Specifies a minimum performance of a mixnode that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_mixnode_performance: u8,
/// Specifies a minimum performance of a gateway that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_gateway_performance: u8,
}
#[allow(clippy::large_enum_variant)]
@@ -578,8 +550,6 @@ impl Default for Topology {
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructure::default(),
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
}
}
}
@@ -95,7 +95,6 @@ impl From<ConfigV5> for Config {
id: value.client.id,
disabled_credentials_mode: value.client.disabled_credentials_mode,
nyxd_urls: value.client.nyxd_urls,
fronting_domains: None, //SW need proper migrations if it gets applied
nym_api_urls: value.client.nym_api_urls,
},
debug: DebugConfig {
@@ -147,7 +146,6 @@ impl From<ConfigV5> for Config {
.topology
.max_startup_gateway_waiting_period,
topology_structure: value.debug.topology.topology_structure.into(),
..Default::default()
},
reply_surbs: ReplySurbs {
minimum_reply_surb_storage_threshold: value
@@ -1,18 +0,0 @@
/*
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
CREATE TABLE remote_gateway_details_temp
(
gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58),
derived_aes128_ctr_blake3_hmac_keys_bs58 TEXT NOT NULL,
gateway_owner_address TEXT,
gateway_listener TEXT NOT NULL,
wg_tun_address TEXT
);
INSERT INTO remote_gateway_details_temp SELECT * FROM remote_gateway_details;
DROP TABLE remote_gateway_details;
ALTER TABLE remote_gateway_details_temp RENAME TO remote_gateway_details;
@@ -65,7 +65,7 @@ impl GatewayDetails {
pub fn new_remote(
gateway_id: identity::PublicKey,
derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
gateway_owner_address: Option<AccountId>,
gateway_owner_address: AccountId,
gateway_listener: Url,
wg_tun_address: Option<Url>,
) -> Self {
@@ -170,7 +170,7 @@ pub struct RegisteredGateway {
pub struct RawRemoteGatewayDetails {
pub gateway_id_bs58: String,
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
pub gateway_owner_address: Option<String>,
pub gateway_owner_address: String,
pub gateway_listener: String,
pub wg_tun_address: Option<String>,
}
@@ -195,19 +195,14 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
})?,
);
let gateway_owner_address = value
.gateway_owner_address
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: raw_owner.clone(),
source,
}
})
})
.transpose()?;
let gateway_owner_address =
AccountId::from_str(&value.gateway_owner_address).map_err(|source| {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: value.gateway_owner_address.clone(),
source,
}
})?;
let gateway_listener = Url::parse(&value.gateway_listener).map_err(|source| {
BadGateway::MalformedListener {
@@ -246,7 +241,7 @@ impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails {
derived_aes128_ctr_blake3_hmac_keys_bs58: value
.derived_aes128_ctr_blake3_hmac_keys
.to_base58_string(),
gateway_owner_address: value.gateway_owner_address.as_ref().map(|o| o.to_string()),
gateway_owner_address: value.gateway_owner_address.to_string(),
gateway_listener: value.gateway_listener.to_string(),
wg_tun_address: value.wg_tun_address.as_ref().map(|addr| addr.to_string()),
}
@@ -261,7 +256,7 @@ pub struct RemoteGatewayDetails {
// the keys will be zeroized
pub derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
pub gateway_owner_address: Option<AccountId>,
pub gateway_owner_address: AccountId,
pub gateway_listener: Url,
@@ -111,7 +111,7 @@ where
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, None).await?
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await?
};
// since we're registering with a brand new gateway,
@@ -70,13 +70,6 @@ pub struct CommonClientInitArgs {
)]
pub nym_apis: Option<Vec<url::Url>>,
///Comma separated list of urls to use for domain fronting
#[cfg_attr(
feature = "cli",
clap(long, value_delimiter = ',', requires = "nym_apis", hide = true)
)]
pub fronting_domains: Option<Vec<url::Url>>,
/// Path to .json file containing custom network specification.
#[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))]
pub custom_mixnet: Option<PathBuf>,
@@ -151,16 +144,6 @@ where
.collect::<Vec<&str>>()
.join(",")
);
if let Some(fronting_domains) = &core.client.fronting_domains {
log::info!(
"fronted by : {}",
fronting_domains
.iter()
.map(|url| url.host_str().unwrap_or_default())
.collect::<Vec<&str>>()
.join(",")
);
}
let key_store = OnDiskKeys::new(paths.keys.clone());
let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?;
@@ -180,12 +163,7 @@ where
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(
&mut rng,
&core.client.nym_api_urls,
core.client.fronting_domains.as_ref(),
)
.await?
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await?
};
let gateway_setup = GatewaySetup::New {
@@ -35,13 +35,6 @@ pub struct CommonClientRunArgs {
)]
pub nym_apis: Option<Vec<url::Url>>,
///Comma separated list of urls to use for domain fronting
#[cfg_attr(
feature = "cli",
clap(long, value_delimiter = ',', requires = "nym_apis", hide = true)
)]
pub fronting_domains: Option<Vec<url::Url>>,
/// Path to .json file containing custom network specification.
#[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))]
pub custom_mixnet: Option<PathBuf>,
@@ -3,7 +3,6 @@
use super::packet_statistics_control::PacketStatisticsReporter;
use super::received_buffer::ReceivedBufferMessage;
use super::topology_control::fronted_api_provider::FrontedApiTopologyProvider;
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
use crate::client::base_client::storage::helpers::store_client_keys;
use crate::client::base_client::storage::MixnetClientStorage;
@@ -26,7 +25,7 @@ use crate::client::replies::reply_storage::{
};
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
use crate::client::topology_control::{
nym_api_provider, TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use crate::config::{Config, DebugConfig};
use crate::error::ClientCoreError;
@@ -389,10 +388,7 @@ where
let cfg = GatewayConfig::new(
details.gateway_id,
details
.gateway_owner_address
.as_ref()
.map(|o| o.to_string()),
Some(details.gateway_owner_address.to_string()),
gateway_listener,
);
GatewayClient::new(
@@ -466,31 +462,15 @@ where
fn setup_topology_provider(
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
config_topology: config::Topology,
provider_from_config: config::TopologyStructure,
nym_api_urls: Vec<Url>,
fronting_domains: Option<Vec<Url>>,
) -> Box<dyn TopologyProvider + Send + Sync> {
// if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| match config_topology.topology_structure {
config::TopologyStructure::NymApi => match fronting_domains {
Some(domains) => Box::new(FrontedApiTopologyProvider::new(
nym_api_provider::Config {
min_mixnode_performance: config_topology.minimum_mixnode_performance,
min_gateway_performance: config_topology.minimum_gateway_performance,
},
nym_api_urls,
domains,
env!("CARGO_PKG_VERSION").to_string(),
)),
None => Box::new(NymApiTopologyProvider::new(
nym_api_provider::Config {
min_mixnode_performance: config_topology.minimum_mixnode_performance,
min_gateway_performance: config_topology.minimum_gateway_performance,
},
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
)),
},
custom_provider.unwrap_or_else(|| match provider_from_config {
config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
)),
config::TopologyStructure::GeoAware(group_by) => {
Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
@@ -700,9 +680,8 @@ where
let topology_provider = Self::setup_topology_provider(
self.custom_topology_provider.take(),
self.config.debug.topology,
self.config.debug.topology.topology_structure,
self.config.get_nym_api_endpoints(),
self.config.get_fronting_domains(),
);
// needs to be started as the first thing to block if required waiting for the gateway
@@ -92,11 +92,11 @@ pub mod v1_1_33 {
message: format!("the stored gateway id was malformed: {err}"),
})?,
derived_aes128_ctr_blake3_hmac_keys: Arc::new(gateway_shared_key),
gateway_owner_address: Some(gateway_owner.parse().map_err(|err| {
gateway_owner_address: gateway_owner.parse().map_err(|err| {
ClientCoreError::UpgradeFailure {
message: format!("the stored gateway owner address was malformed: {err}"),
}
})?),
})?,
gateway_listener: gateway_listener.parse().map_err(|err| {
ClientCoreError::UpgradeFailure {
message: format!("the stored gateway listener address was malformed: {err}"),
@@ -1,147 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{debug, error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{NymTopology, NymTopologyError};
use rand::prelude::SliceRandom;
use rand::thread_rng;
use url::Url;
use super::nym_api_provider::Config;
pub(crate) struct FrontedApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
nym_api_urls: Vec<Url>,
fronting_domains: Vec<Url>,
shuffling: Vec<usize>,
client_version: String,
currently_used_api: usize,
}
impl FrontedApiTopologyProvider {
pub(crate) fn new(
config: Config,
nym_api_urls: Vec<Url>,
fronting_domains: Vec<Url>,
client_version: String,
) -> Self {
//SW for the PoC, we assume same lenght between fronting domains and api_urls
let mut shuffling = (0..nym_api_urls.len()).collect::<Vec<_>>();
shuffling.shuffle(&mut thread_rng());
FrontedApiTopologyProvider {
config,
validator_client: nym_validator_client::client::NymApiClient::new_fronted(
nym_api_urls[shuffling[0]].clone(),
fronting_domains[shuffling[0]].clone(),
),
nym_api_urls,
fronting_domains,
shuffling,
client_version,
currently_used_api: 0,
}
}
fn use_next_nym_api(&mut self) {
if self.nym_api_urls.len() == 1 {
warn!("There's only a single nym API available - it won't be possible to use a different one");
return;
}
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
self.validator_client.change_nym_api_with_fronting(
self.nym_api_urls[self.shuffling[self.currently_used_api]].clone(),
self.fronting_domains[self.shuffling[self.currently_used_api]].clone(),
);
}
/// Verifies whether nodes a reasonably distributed among all mix layers.
///
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
/// However, this is a rather unrealistic expectation, instead we check whether there exists
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
///
/// # Arguments
///
/// * `topology`: active topology constructed from validator api data
fn check_layer_distribution(
&self,
active_topology: &NymTopology,
) -> Result<(), NymTopologyError> {
let lower_threshold = 0.15;
let upper_threshold = 0.66;
active_topology.ensure_even_layer_distribution(lower_threshold, upper_threshold)
}
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_mixnodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
}
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_basic_gateways(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
}
Ok(gateways) => gateways,
};
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
let topology = NymTopology::from_unordered(
mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
}),
gateways.iter().filter(|g| {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api();
None
} else {
Some(topology)
}
}
}
// hehe, wasm
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
impl TopologyProvider for FrontedApiTopologyProvider {
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_current_compatible_topology().await
}
}
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
impl TopologyProvider for FrontedApiTopologyProvider {
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_current_compatible_topology().await
}
}
@@ -17,7 +17,6 @@ use tokio::time::sleep;
use wasmtimer::tokio::sleep;
mod accessor;
pub(crate) mod fronted_api_provider;
pub mod geo_aware_provider;
pub(crate) mod nym_api_provider;
@@ -2,35 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{debug, error, warn};
use log::{error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{NymTopology, NymTopologyError};
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
use rand::prelude::SliceRandom;
use rand::thread_rng;
use url::Url;
// the same values as our current (10.06.24) blacklist
pub const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50;
pub const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50;
pub(crate) struct Config {
pub(crate) min_mixnode_performance: u8,
pub(crate) min_gateway_performance: u8,
}
impl Default for Config {
fn default() -> Self {
// old values that decided on blacklist membership
Config {
min_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
min_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
}
}
}
pub(crate) struct NymApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
nym_api_urls: Vec<Url>,
@@ -39,11 +18,10 @@ pub(crate) struct NymApiTopologyProvider {
}
impl NymApiTopologyProvider {
pub(crate) fn new(config: Config, mut nym_api_urls: Vec<Url>, client_version: String) -> Self {
pub(crate) fn new(mut nym_api_urls: Vec<Url>, client_version: String) -> Self {
nym_api_urls.shuffle(&mut thread_rng());
NymApiTopologyProvider {
config,
validator_client: nym_validator_client::client::NymApiClient::new(
nym_api_urls[0].clone(),
),
@@ -83,11 +61,7 @@ impl NymApiTopologyProvider {
}
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_mixnodes(Some(self.client_version.clone()))
.await
{
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
@@ -95,11 +69,7 @@ impl NymApiTopologyProvider {
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_basic_gateways(Some(self.client_version.clone()))
.await
{
let gateways = match self.validator_client.get_cached_described_gateways().await {
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
@@ -107,20 +77,8 @@ impl NymApiTopologyProvider {
Ok(gateways) => gateways,
};
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
let topology = NymTopology::from_unordered(
mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
}),
gateways.iter().filter(|g| {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
+5 -22
View File
@@ -9,7 +9,6 @@ use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_topology::{filter::VersionFilterable, gateway, mix};
use nym_validator_client::client::IdentityKeyRef;
use rand::seq::IteratorRandom;
use rand::{seq::SliceRandom, Rng};
use std::{sync::Arc, time::Duration};
use tungstenite::Message;
@@ -60,29 +59,13 @@ impl<'a> GatewayWithLatency<'a> {
pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
fronting_domains: Option<&Vec<Url>>,
) -> Result<Vec<gateway::Node>, ClientCoreError> {
let client = match fronting_domains {
Some(domains) => {
let (api_url, fronting_url) = nym_apis
.iter()
.zip(domains)
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
nym_validator_client::client::NymApiClient::new_fronted(
api_url.clone(),
fronting_url.clone(),
)
}
None => {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
nym_validator_client::client::NymApiClient::new(nym_api.clone())
}
};
log::debug!("Fetching list of gateways from: {}", client.api_url());
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_cached_described_gateways().await?;
log::debug!("Found {} gateways", gateways.len());
+8 -14
View File
@@ -29,7 +29,7 @@ pub enum SelectedGateway {
Remote {
gateway_id: identity::PublicKey,
gateway_owner_address: Option<AccountId>,
gateway_owner_address: AccountId,
gateway_listener: Url,
@@ -84,19 +84,13 @@ impl SelectedGateway {
let wg_tun_address = wg_tun_address(wg_tun_ip_address, &node)?;
let gateway_owner_address = node
.owner
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: raw_owner.clone(),
err: source.to_string(),
}
})
})
.transpose()?;
let gateway_owner_address = AccountId::from_str(&node.owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: node.owner,
err: source.to_string(),
}
})?;
let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
@@ -14,6 +14,7 @@ colored = { workspace = true }
nym-coconut-dkg-common = { path = "../../cosmwasm-smart-contracts/coconut-dkg" }
nym-contracts-common = { path = "../../cosmwasm-smart-contracts/contracts-common" }
nym-ephemera-common = { path = "../../cosmwasm-smart-contracts/ephemera" }
nym-mixnet-contract-common = { path = "../../cosmwasm-smart-contracts/mixnet-contract" }
nym-vesting-contract-common = { path = "../../cosmwasm-smart-contracts/vesting-contract" }
nym-coconut-bandwidth-contract-common = { path = "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
@@ -21,7 +22,7 @@ nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" }
nym-http-api-client = { path = "../../../common/http-api-client"}
thiserror = { workspace = true }
log = { workspace = true }
url = { workspace = true, features = ["serde"] }
@@ -18,7 +18,6 @@ use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_network_defaults::NymNetworkDetails;
use url::Url;
@@ -258,12 +257,6 @@ impl NymApiClient {
NymApiClient { nym_api }
}
pub fn new_fronted(api_url: Url, fronting_url: Url) -> Self {
let nym_api = nym_api::Client::new_fronted(api_url, fronting_url, None);
NymApiClient { nym_api }
}
pub fn api_url(&self) -> &Url {
self.nym_api.current_url()
}
@@ -272,37 +265,6 @@ impl NymApiClient {
self.nym_api.change_base_url(new_endpoint);
}
pub fn change_nym_api_with_fronting(
&mut self,
new_api_endpoint: Url,
new_fronting_domain: Url,
) {
self.nym_api
.change_fronted_url(new_api_endpoint, new_fronting_domain);
}
pub async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self
.nym_api
.get_basic_mixnodes(semver_compatibility)
.await?
.nodes)
}
pub async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self
.nym_api
.get_basic_gateways(semver_compatibility)
.await?
.nodes)
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
@@ -31,7 +31,6 @@ pub mod routes;
use nym_api_requests::coconut::models::FreePassNonceResponse;
use nym_api_requests::coconut::FreePassRequest;
use nym_api_requests::nym_nodes::{CachedNodesResponse, SkimmedNode};
pub use nym_http_api_client::Client;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -96,52 +95,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
let params = if let Some(semver_compatibility) = &semver_compatibility {
vec![("semver_compatibility", semver_compatibility.as_str())]
} else {
vec![]
};
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"mixnodes",
"skimmed",
],
&params,
)
.await
}
async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
let params = if let Some(semver_compatibility) = &semver_compatibility {
vec![("semver_compatibility", semver_compatibility.as_str())]
} else {
vec![]
};
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"gateways",
"skimmed",
],
&params,
)
.await
}
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
@@ -0,0 +1,79 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::collect_paged;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use nym_ephemera_common::msg::QueryMsg as EphemeraQueryMsg;
use nym_ephemera_common::peers::PagedPeerResponse;
use nym_ephemera_common::types::JsonPeerInfo;
use serde::Deserialize;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait EphemeraQueryClient {
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn get_peers_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedPeerResponse, NyxdError> {
let request = EphemeraQueryMsg::GetPeers { start_after, limit };
self.query_ephemera_contract(request).await
}
}
// extension trait to the query client to deal with the paged queries
// (it didn't feel appropriate to combine it with the existing trait
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedEphemeraQueryClient: EphemeraQueryClient {
async fn get_all_ephemera_peers(&self) -> Result<Vec<JsonPeerInfo>, NyxdError> {
collect_paged!(self, get_peers_paged, peers)
}
}
#[async_trait]
impl<T> PagedEphemeraQueryClient for T where T: EphemeraQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> EphemeraQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let ephemera_contract_address = &self
.ephemera_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
self.query_contract_smart(ephemera_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_query_variants_are_covered<C: EphemeraQueryClient + Send + Sync>(
client: C,
msg: EphemeraQueryMsg,
) {
match msg {
EphemeraQueryMsg::GetPeers { limit, start_after } => {
client.get_peers_paged(start_after, limit).ignore()
}
};
}
}
@@ -0,0 +1,86 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use nym_ephemera_common::msg::ExecuteMsg as EphemeraExecuteMsg;
use nym_ephemera_common::types::JsonPeerInfo;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait EphemeraSigningClient {
async fn execute_ephemera_contract(
&self,
fee: Option<Fee>,
msg: EphemeraExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn register_as_peer(
&self,
peer_info: JsonPeerInfo,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = EphemeraExecuteMsg::RegisterPeer { peer_info };
self.execute_ephemera_contract(fee, req, "registering as peer".to_string(), vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> EphemeraSigningClient for C
where
C: SigningCosmWasmClient + NymContractsProvider + Sync,
NyxdError: From<<Self as OfflineSigner>::Error>,
{
async fn execute_ephemera_contract(
&self,
fee: Option<Fee>,
msg: EphemeraExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError> {
let ephemera_contract_address = self
.ephemera_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
let signer_address = &self.signer_addresses()?[0];
self.execute(
signer_address,
ephemera_contract_address,
&msg,
fee,
memo,
funds,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_execute_variants_are_covered<C: EphemeraSigningClient + Send + Sync>(
client: C,
msg: EphemeraExecuteMsg,
) {
match msg {
EphemeraExecuteMsg::RegisterPeer { peer_info } => {
client.register_as_peer(peer_info, None).ignore()
}
};
}
}
@@ -10,6 +10,7 @@ use std::str::FromStr;
// query clients
pub mod coconut_bandwidth_query_client;
pub mod dkg_query_client;
pub mod ephemera_query_client;
pub mod group_query_client;
pub mod mixnet_query_client;
pub mod multisig_query_client;
@@ -18,6 +19,7 @@ pub mod vesting_query_client;
// signing clients
pub mod coconut_bandwidth_signing_client;
pub mod dkg_signing_client;
pub mod ephemera_signing_client;
pub mod group_signing_client;
pub mod mixnet_signing_client;
pub mod multisig_signing_client;
@@ -28,6 +30,7 @@ pub use coconut_bandwidth_query_client::{
CoconutBandwidthQueryClient, PagedCoconutBandwidthQueryClient,
};
pub use dkg_query_client::{DkgQueryClient, PagedDkgQueryClient};
pub use ephemera_query_client::{EphemeraQueryClient, PagedEphemeraQueryClient};
pub use group_query_client::{GroupQueryClient, PagedGroupQueryClient};
pub use mixnet_query_client::{MixnetQueryClient, PagedMixnetQueryClient};
pub use multisig_query_client::{MultisigQueryClient, PagedMultisigQueryClient};
@@ -36,6 +39,7 @@ pub use vesting_query_client::{PagedVestingQueryClient, VestingQueryClient};
// re-export signing traits
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
pub use dkg_signing_client::DkgSigningClient;
pub use ephemera_signing_client::EphemeraSigningClient;
pub use group_signing_client::GroupSigningClient;
pub use mixnet_signing_client::MixnetSigningClient;
pub use multisig_signing_client::MultisigSigningClient;
@@ -52,6 +56,9 @@ pub trait NymContractsProvider {
fn dkg_contract_address(&self) -> Option<&AccountId>;
fn group_contract_address(&self) -> Option<&AccountId>;
fn multisig_contract_address(&self) -> Option<&AccountId>;
// ephemera-related
fn ephemera_contract_address(&self) -> Option<&AccountId>;
}
#[derive(Debug, Clone)]
@@ -63,6 +70,8 @@ pub struct TypedNymContracts {
pub group_contract_address: Option<AccountId>,
pub multisig_contract_address: Option<AccountId>,
pub coconut_dkg_contract_address: Option<AccountId>,
pub ephemera_contract_address: Option<AccountId>,
}
impl TryFrom<NymContracts> for TypedNymContracts {
@@ -94,6 +103,10 @@ impl TryFrom<NymContracts> for TypedNymContracts {
.coconut_dkg_contract_address
.map(|addr| addr.parse())
.transpose()?,
ephemera_contract_address: value
.ephemera_contract_address
.map(|addr| addr.parse())
.transpose()?,
})
}
}
@@ -9,12 +9,16 @@ pub use nym_coconut_bandwidth_contract_common::event_attributes::*;
pub use nym_coconut_dkg_common::event_attributes::*;
// it seems that currently validators just emit stringified events (which are also returned as part of deliverTx response)
// as their logs
// as theirs logs
#[derive(Debug, Serialize, Deserialize)]
pub struct Log {
#[serde(default)]
// weird thing is that the first msg_index seems to always be undefined on the raw logs
pub msg_index: usize,
// unless I'm missing something obvious, the "log" type in cosmjs is always an empty string
// and launchpad cosmos validator was setting it to what essentially is just the raw version of what
// we received (and we don't care about launchpad, we, as the time of writing this, work on the stargate)
// log: String,
pub events: Vec<cosmwasm_std::Event>,
}
@@ -33,12 +37,8 @@ pub fn find_attribute<'a>(
.find(|attr| attr.key == attribute_key)
}
// these two functions were separated so that the internal logic could actually be tested
// those two functions were separated so that the internal logic could actually be tested
fn parse_raw_str_logs(raw: &str) -> Result<Vec<Log>, NyxdError> {
if raw.is_empty() {
return Ok(Vec::new());
}
let logs: Vec<Log> = serde_json::from_str(raw).map_err(|_| NyxdError::MalformedLogString)?;
if logs.len() != logs.iter().unique_by(|log| log.msg_index).count() {
// this check is only here because I don't yet fully understand raw log string generation and
@@ -140,6 +140,6 @@ mod tests {
let fee = &gas_price * gas_limit;
// the failing behaviour was result value of 3937
assert_eq!(fee.amount, 3938u128);
assert_eq!(fee.amount, 3938u64.into());
}
}
@@ -70,8 +70,6 @@ use crate::http_client;
use crate::{DirectSigningHttpRpcNyxdClient, QueryHttpRpcNyxdClient};
#[cfg(feature = "http-client")]
use cosmrs::rpc::{HttpClient, HttpClientUrl};
use nym_contracts_common::build_information::CONTRACT_BUILD_INFO_STORAGE_KEY;
use nym_contracts_common::ContractBuildInformation;
pub mod coin;
pub mod contract_traits;
@@ -280,6 +278,10 @@ impl<C, S> NymContractsProvider for NyxdClient<C, S> {
fn multisig_contract_address(&self) -> Option<&AccountId> {
self.config.contracts.multisig_contract_address.as_ref()
}
fn ephemera_contract_address(&self) -> Option<&AccountId> {
self.config.contracts.ephemera_contract_address.as_ref()
}
}
// queries
@@ -330,33 +332,6 @@ where
.await
.map(|block| block.block_id.hash)
}
pub async fn try_get_cw2_contract_version(
&self,
contract_address: &AccountId,
) -> Option<cw2::ContractVersion> {
let raw_info = self
.query_contract_raw(contract_address, b"contract_info".to_vec())
.await
.ok()?;
serde_json::from_slice(&raw_info).ok()
}
pub async fn try_get_contract_build_information(
&self,
contract_address: &AccountId,
) -> Option<ContractBuildInformation> {
let raw_info = self
.query_contract_raw(
contract_address,
CONTRACT_BUILD_INFO_STORAGE_KEY.as_bytes().to_vec(),
)
.await
.ok()?;
serde_json::from_slice(&raw_info).ok()
}
}
// signing
@@ -11,13 +11,9 @@ repository = { workspace = true }
bs58 = { workspace = true }
cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
cw-storage-plus = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
[dev-dependencies]
serde_json = { workspace = true }
[build-dependencies]
vergen = { version = "=8.3.1", features = ["build", "git", "gitcl", "rustc", "cargo"] }
@@ -1,17 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use vergen::EmitBuilder;
fn main() {
EmitBuilder::builder()
.all_build()
.rustc_semver()
.git_branch()
.git_commit_timestamp()
.git_sha(false)
.cargo_debug()
.cargo_opt_level()
.emit()
.expect("failed to extract build metadata");
}
@@ -1,85 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ContractBuildInformation;
use cosmwasm_std::{StdResult, Storage};
use cw_storage_plus::Item;
pub const CONTRACT_BUILD_INFO_STORAGE_KEY: &str = "contract_build_info";
pub const CONTRACT_BUILD_INFO: Item<ContractBuildInformation> =
Item::new(CONTRACT_BUILD_INFO_STORAGE_KEY);
// important note. this MUST BE called inside the contract code itself and not any intermediate crate
// otherwise macro expansions will resolve to incorrect data
#[macro_export]
macro_rules! get_build_information {
() => {
$crate::types::ContractBuildInformation::new(
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
)
};
}
pub fn set_state_build_information(
store: &mut dyn Storage,
build_info: ContractBuildInformation,
) -> StdResult<()> {
CONTRACT_BUILD_INFO.save(store, &build_info)
}
pub fn get_contract_build_information(store: &dyn Storage) -> StdResult<ContractBuildInformation> {
CONTRACT_BUILD_INFO.load(store)
}
#[macro_export]
macro_rules! set_build_information {
( $store:expr ) => {
$crate::build_information::set_state_build_information(
$store,
$crate::get_build_information!(),
)
};
}
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::MockStorage;
#[test]
fn get_and_set_work() {
let mut store = MockStorage::new();
// error if not set
assert!(get_contract_build_information(&store).is_err());
// set and get
let contract_name = "nym-mixnet-contract";
let contract_version = "1.2.3";
let build_info = ContractBuildInformation::new(contract_name, contract_version);
set_state_build_information(&mut store, build_info).unwrap();
let loaded = get_contract_build_information(&store).unwrap();
let expected = ContractBuildInformation {
contract_name: contract_name.into(),
build_version: contract_version.into(),
build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(),
commit_sha: option_env!("VERGEN_GIT_SHA")
.unwrap_or("UNKNOWN")
.to_string(),
commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP")
.unwrap_or("UNKNOWN")
.to_string(),
commit_branch: option_env!("VERGEN_GIT_BRANCH")
.unwrap_or("UNKNOWN")
.to_string(),
rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(),
cargo_debug: env!("VERGEN_CARGO_DEBUG").to_string(),
cargo_opt_level: env!("VERGEN_CARGO_OPT_LEVEL").to_string(),
};
assert_eq!(expected, loaded);
}
}
@@ -4,7 +4,6 @@
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
pub mod build_information;
pub mod dealings;
pub mod events;
pub mod signing;
@@ -132,18 +132,10 @@ where
}
}
fn default_unknown() -> String {
"unknown".to_string()
}
// TODO: there's no reason this couldn't be used for proper binaries, but in that case
// perhaps the struct should get renamed and moved to a "more" common crate
#[cw_serde]
pub struct ContractBuildInformation {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
#[serde(default = "default_unknown")]
pub contract_name: String,
// VERGEN_BUILD_TIMESTAMP
/// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`.
pub build_timestamp: String,
@@ -167,38 +159,6 @@ pub struct ContractBuildInformation {
// VERGEN_RUSTC_SEMVER
/// Provides the rustc version that was used for the build, for example `1.52.0-nightly`.
pub rustc_version: String,
// VERGEN_CARGO_DEBUG
/// Provides the cargo debug mode that was used for the build.
#[serde(default = "default_unknown")]
pub cargo_debug: String,
// VERGEN_CARGO_OPT_LEVEL
/// Provides the opt value set by cargo during the build
#[serde(default = "default_unknown")]
pub cargo_opt_level: String,
}
impl ContractBuildInformation {
pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
ContractBuildInformation {
contract_name: name.into(),
build_version: version.into(),
build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(),
commit_sha: option_env!("VERGEN_GIT_SHA")
.unwrap_or("UNKNOWN")
.to_string(),
commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP")
.unwrap_or("UNKNOWN")
.to_string(),
commit_branch: option_env!("VERGEN_GIT_BRANCH")
.unwrap_or("UNKNOWN")
.to_string(),
rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(),
cargo_debug: env!("VERGEN_CARGO_DEBUG").to_string(),
cargo_opt_level: env!("VERGEN_CARGO_OPT_LEVEL").to_string(),
}
}
}
#[cfg(test)]
@@ -0,0 +1,17 @@
[package]
name = "nym-ephemera-common"
version = "0.1.0"
edition = "2021"
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true }
cw-utils = { workspace = true }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common" }
[features]
schema = []
@@ -0,0 +1,3 @@
pub mod msg;
pub mod peers;
pub mod types;
@@ -0,0 +1,33 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "schema")]
use crate::peers::PagedPeerResponse;
use crate::types::JsonPeerInfo;
use cosmwasm_schema::cw_serde;
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cw_serde]
pub struct InstantiateMsg {
pub group_addr: String,
pub mix_denom: String,
}
#[cw_serde]
pub enum ExecuteMsg {
RegisterPeer { peer_info: JsonPeerInfo },
}
#[cw_serde]
#[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg {
#[cfg_attr(feature = "schema", returns(PagedPeerResponse))]
GetPeers {
limit: Option<u32>,
start_after: Option<String>,
},
}
#[cw_serde]
pub struct MigrateMsg {}
@@ -0,0 +1,25 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::JsonPeerInfo;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
#[cw_serde]
pub struct PagedPeerResponse {
pub peers: Vec<JsonPeerInfo>,
pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>,
}
impl PagedPeerResponse {
pub fn new(peers: Vec<JsonPeerInfo>, per_page: usize, start_next_after: Option<Addr>) -> Self {
PagedPeerResponse {
peers,
per_page,
start_next_after,
}
}
}
@@ -0,0 +1,29 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
#[cw_serde]
pub struct JsonPeerInfo {
/// The cosmos address of the peer, used in interacting with the chain.
pub cosmos_address: Addr,
/// The TCP/IP address of the peer.
/// Expected formats:
/// 1. `<IP>:<PORT>`
/// 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr
pub ip_address: String,
///Serialized public key.
pub public_key: String,
}
impl JsonPeerInfo {
#[must_use]
pub fn new(cosmos_address: Addr, ip_address: String, public_key: String) -> Self {
Self {
cosmos_address,
ip_address,
public_key,
}
}
}
@@ -234,6 +234,12 @@ pub enum MixnetContractError {
#[error("the epoch is currently not in the 'epoch advancement' state. (the state is {current_state})")]
EpochNotInAdvancementState { current_state: EpochState },
#[error("failed to parse {value} into a valid SemVer version: {error_message}")]
SemVerFailure {
value: String,
error_message: String,
},
#[error("failed to verify message signature: {source}")]
SignatureVerificationFailure {
#[from]
-40
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use http::header;
use reqwest::header::HeaderValue;
use reqwest::{RequestBuilder, Response, StatusCode};
use serde::de::DeserializeOwned;
@@ -97,13 +96,6 @@ impl ClientBuilder {
self
}
pub fn with_host_header(mut self, host: &str) -> Self {
let mut headers = header::HeaderMap::new();
headers.insert(header::HOST, HeaderValue::from_str(host).unwrap()); //SW Handle this unwrap later
self.reqwest_client_builder = self.reqwest_client_builder.default_headers(headers);
self
}
pub fn with_user_agent<V>(mut self, value: V) -> Self
where
V: TryInto<HeaderValue>,
@@ -163,23 +155,6 @@ impl Client {
)
}
pub fn new_fronted(base_url: Url, fronting_url: Url, timeout: Option<Duration>) -> Self {
let host = base_url.host_str().unwrap();
let mut fronted_url = base_url.clone();
fronted_url.set_host(fronting_url.host_str()).unwrap();
let builder = ClientBuilder::new::<_, String>(fronted_url)
.expect(
"we provided valid url and we were unwrapping previous construction errors anyway",
)
.with_host_header(host);
//SW polish that later if needed
match timeout {
Some(timeout) => builder.with_timeout(timeout).build::<String>().unwrap(),
None => builder.build::<String>().unwrap(),
}
}
pub fn new_url<U, E>(url: U, timeout: Option<Duration>) -> Result<Self, HttpClientError<E>>
where
U: IntoUrl,
@@ -204,21 +179,6 @@ impl Client {
self.base_url = new_url
}
pub fn change_fronted_url(&mut self, new_api_url: Url, new_fronting_url: Url) {
let host = new_api_url.host_str().unwrap();
let mut new_fronted_url = new_api_url.clone();
new_fronted_url
.set_host(new_fronting_url.host_str())
.unwrap();
let mut headers = header::HeaderMap::new();
headers.insert(header::HOST, HeaderValue::from_str(host).unwrap()); //SW Handle this unwrap later
self.reqwest_client = reqwest::ClientBuilder::new()
.default_headers(headers)
.build()
.unwrap();
self.base_url = new_fronted_url
}
pub fn current_url(&self) -> &Url {
&self.base_url
}
+42 -1
View File
@@ -31,6 +31,9 @@ pub struct NymContracts {
pub group_contract_address: Option<String>,
pub multisig_contract_address: Option<String>,
pub coconut_dkg_contract_address: Option<String>,
pub ephemera_contract_address: Option<String>,
pub service_provider_directory_contract_address: Option<String>,
pub name_service_contract_address: Option<String>,
}
// I wanted to use the simpler `NetworkDetails` name, but there's a clash
@@ -125,6 +128,11 @@ impl NymNetworkDetails {
.with_group_contract(get_optional_env(var_names::GROUP_CONTRACT_ADDRESS))
.with_multisig_contract(get_optional_env(var_names::MULTISIG_CONTRACT_ADDRESS))
.with_coconut_dkg_contract(get_optional_env(var_names::COCONUT_DKG_CONTRACT_ADDRESS))
.with_ephemera_contract(get_optional_env(var_names::EPHEMERA_CONTRACT_ADDRESS))
.with_service_provider_directory_contract(get_optional_env(
var_names::SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS,
))
.with_name_service_contract(get_optional_env(var_names::NAME_SERVICE_CONTRACT_ADDRESS))
.with_explorer_api(get_optional_env(var_names::EXPLORER_API))
}
@@ -153,6 +161,9 @@ impl NymNetworkDetails {
coconut_dkg_contract_address: parse_optional_str(
mainnet::COCONUT_DKG_CONTRACT_ADDRESS,
),
ephemera_contract_address: parse_optional_str(mainnet::EPHEMERA_CONTRACT_ADDRESS),
service_provider_directory_contract_address: None,
name_service_contract_address: None,
},
explorer_api: parse_optional_str(mainnet::EXPLORER_API),
}
@@ -258,6 +269,27 @@ impl NymNetworkDetails {
self
}
#[must_use]
pub fn with_ephemera_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.ephemera_contract_address = contract.map(Into::into);
self
}
#[must_use]
pub fn with_service_provider_directory_contract<S: Into<String>>(
mut self,
contract: Option<S>,
) -> Self {
self.contracts.service_provider_directory_contract_address = contract.map(Into::into);
self
}
#[must_use]
pub fn with_name_service_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.name_service_contract_address = contract.map(Into::into);
self
}
#[must_use]
pub fn with_explorer_api<S: Into<String>>(mut self, endpoint: Option<S>) -> Self {
self.explorer_api = endpoint.map(Into::into);
@@ -421,13 +453,22 @@ pub fn setup_env<P: AsRef<Path>>(config_env_file: Option<P>) {
}
}
// Name of the event triggered by the eth contract. If the event name is changed,
// this would also need to be changed; It is currently tested against the json abi
pub const ETH_EVENT_NAME: &str = "BBCredentialPurchased";
pub const ETH_BURN_FUNCTION_NAME: &str = "generateBasicBandwidthCredential";
pub const ETH_ERC20_APPROVE_FUNCTION_NAME: &str = "approve";
// Ethereum constants used for token bridge
/// How much bandwidth (in bytes) one token can buy
pub const BYTES_PER_UTOKEN: u64 = 1024;
/// How much bandwidth (in bytes) one freepass provides
pub const BYTES_PER_FREEPASS: u64 = 1024 * 1024 * 1024; // 1GB
/// Threshold for claiming more bandwidth: 1 MB
pub const REMAINING_BANDWIDTH_THRESHOLD: i64 = 1024 * 1024;
/// How many tokens should be burned to buy bandwidth
/// How many ERC20 tokens should be burned to buy bandwidth
pub const TOKENS_TO_BURN: u64 = 1;
/// How many ERC20 utokens should be burned to buy bandwidth
pub const UTOKENS_TO_BURN: u64 = TOKENS_TO_BURN * 1000000;
+9
View File
@@ -24,6 +24,7 @@ pub const MULTISIG_CONTRACT_ADDRESS: &str =
"n1txayqfz5g9qww3rlflpg025xd26m9payz96u54x4fe3s2ktz39xqk67gzx";
pub const COCONUT_DKG_CONTRACT_ADDRESS: &str =
"n19604yflqggs9mk2z26mqygq43q2kr3n932egxx630svywd5mpxjsztfpvx";
pub const EPHEMERA_CONTRACT_ADDRESS: &str = "";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
@@ -106,6 +107,10 @@ pub fn export_to_env() {
var_names::COCONUT_DKG_CONTRACT_ADDRESS,
COCONUT_DKG_CONTRACT_ADDRESS,
);
set_var_to_default(
var_names::EPHEMERA_CONTRACT_ADDRESS,
EPHEMERA_CONTRACT_ADDRESS,
);
set_var_to_default(
var_names::REWARDING_VALIDATOR_ADDRESS,
REWARDING_VALIDATOR_ADDRESS,
@@ -151,6 +156,10 @@ pub fn export_to_env_if_not_set() {
var_names::COCONUT_DKG_CONTRACT_ADDRESS,
COCONUT_DKG_CONTRACT_ADDRESS,
);
set_var_conditionally_to_default(
var_names::EPHEMERA_CONTRACT_ADDRESS,
EPHEMERA_CONTRACT_ADDRESS,
);
set_var_conditionally_to_default(
var_names::REWARDING_VALIDATOR_ADDRESS,
REWARDING_VALIDATOR_ADDRESS,
+4
View File
@@ -18,8 +18,12 @@ pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "COCONUT_BANDWIDTH_CONTRACT
pub const GROUP_CONTRACT_ADDRESS: &str = "GROUP_CONTRACT_ADDRESS";
pub const MULTISIG_CONTRACT_ADDRESS: &str = "MULTISIG_CONTRACT_ADDRESS";
pub const COCONUT_DKG_CONTRACT_ADDRESS: &str = "COCONUT_DKG_CONTRACT_ADDRESS";
pub const EPHEMERA_CONTRACT_ADDRESS: &str = "EPHEMERA_CONTRACT_ADDRESS";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
pub const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "STATISTICS_SERVICE_DOMAIN_ADDRESS";
pub const SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS: &str =
"SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS";
pub const NAME_SERVICE_CONTRACT_ADDRESS: &str = "NAME_SERVICE_CONTRACT_ADDRESS";
pub const NYXD: &str = "NYXD";
pub const NYM_API: &str = "NYM_API";
pub const NYXD_WEBSOCKET: &str = "NYXD_WS";
+2 -2
View File
@@ -41,7 +41,7 @@ impl<'a> From<&'a mix::Node> for TestableNode {
fn from(value: &'a mix::Node) -> Self {
TestableNode {
encoded_identity: value.identity_key.to_base58_string(),
owner: value.owner.as_ref().cloned().unwrap_or_default(),
owner: value.owner.clone(),
typ: NodeType::Mixnode {
mix_id: value.mix_id,
},
@@ -53,7 +53,7 @@ impl<'a> From<&'a gateway::Node> for TestableNode {
fn from(value: &'a gateway::Node) -> Self {
TestableNode {
encoded_identity: value.identity_key.to_base58_string(),
owner: value.owner.as_ref().cloned().unwrap_or_default(),
owner: value.owner.clone(),
typ: NodeType::Gateway,
}
}
+5 -9
View File
@@ -6,7 +6,6 @@ use nym_credential_storage::models::StorableIssuedCredential;
use nym_credential_storage::storage::Storage;
use nym_credentials::coconut::bandwidth::issued::BandwidthCredentialIssuedDataVariant;
use nym_credentials::IssuedBandwidthCredential;
use time::OffsetDateTime;
use tracing::{debug, warn};
use zeroize::Zeroizing;
@@ -14,7 +13,7 @@ pub async fn import_credential<S>(
credentials_store: S,
raw_credential: Vec<u8>,
credential_version: impl Into<Option<u8>>,
) -> Result<Option<OffsetDateTime>, NymIdError>
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
@@ -30,10 +29,9 @@ where
credential.typ()
);
let expiry_date = match credential.variant_data() {
match credential.variant_data() {
BandwidthCredentialIssuedDataVariant::Voucher(voucher_info) => {
debug!("with value of {}", voucher_info.value());
None
debug!("with value of {}", voucher_info.value())
}
BandwidthCredentialIssuedDataVariant::FreePass(freepass_info) => {
debug!("with expiry at {}", freepass_info.expiry_date());
@@ -44,11 +42,9 @@ where
return Err(NymIdError::ExpiredCredentialImport {
expiration: freepass_info.expiry_date(),
});
} else {
Some(freepass_info.expiry_date())
}
}
};
}
// SAFETY:
// for the epoch to run over u32::MAX, we'd have to advance it for few centuries every block...
@@ -71,5 +67,5 @@ where
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?;
Ok(expiry_date)
Ok(())
}
+48 -18
View File
@@ -300,8 +300,8 @@ impl Fragment {
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct FragmentHeader {
/// ID associated with `FragmentSet` to which this particular `Fragment` belongs.
/// Its value is restricted to (0, i32::MAX].
/// Note that it *excludes* 0, but *includes* i32::MAX.
/// Its value is restricted to (0, i32::max_value()].
/// Note that it *excludes* 0, but *includes* i32::max_value().
/// This allows the field to be represented using 31 bits.
id: i32,
@@ -319,7 +319,7 @@ pub(crate) struct FragmentHeader {
previous_fragments_set_id: Option<i32>,
/// Optional ID of next `FragmentSet` into which the original message was split.
/// Note, this option is only valid of `current_fragment == total_fragments == u8::MAX`
/// Note, this option is only valid of `current_fragment == total_fragments == u8::max_value()`
next_fragments_set_id: Option<i32>,
}
@@ -414,7 +414,7 @@ impl FragmentHeader {
if current_fragment == 1 {
previous_fragments_set_id = Some(linked_id);
} else if total_fragments == current_fragment && current_fragment == u8::MAX {
} else if total_fragments == current_fragment && current_fragment == u8::max_value() {
next_fragments_set_id = Some(linked_id);
} else {
return Err(ChunkingError::MalformedHeaderError);
@@ -585,7 +585,14 @@ mod fragment_tests {
rng.fill_bytes(&mut msg);
let fragment = Fragment {
header: FragmentHeader::try_new(12345, u8::MAX, u8::MAX, None, Some(1234)).unwrap(),
header: FragmentHeader::try_new(
12345,
u8::max_value(),
u8::max_value(),
None,
Some(1234),
)
.unwrap(),
payload: msg,
};
let packet_bytes = fragment.clone().into_bytes();
@@ -595,7 +602,14 @@ mod fragment_tests {
rng.fill_bytes(&mut msg);
let fragment = Fragment {
header: FragmentHeader::try_new(12345, u8::MAX, u8::MAX, None, Some(1234)).unwrap(),
header: FragmentHeader::try_new(
12345,
u8::max_value(),
u8::max_value(),
None,
Some(1234),
)
.unwrap(),
payload: msg,
};
let packet_bytes = fragment.clone().into_bytes();
@@ -808,8 +822,8 @@ mod fragment_tests {
assert!(Fragment::try_new(
&full_payload,
id,
u8::MAX,
u8::MAX,
u8::max_value(),
u8::max_value(),
None,
Some(link_id),
max_plaintext_size(),
@@ -870,8 +884,8 @@ mod fragment_tests {
assert!(Fragment::try_new(
&non_full_payload,
id,
u8::MAX,
u8::MAX,
u8::max_value(),
u8::max_value(),
None,
Some(link_id),
max_plaintext_size(),
@@ -880,8 +894,8 @@ mod fragment_tests {
assert!(Fragment::try_new(
&non_full_payload2,
id,
u8::MAX,
u8::MAX,
u8::max_value(),
u8::max_value(),
None,
Some(link_id),
max_plaintext_size(),
@@ -891,8 +905,8 @@ mod fragment_tests {
assert!(Fragment::try_new(
&too_much_payload,
id,
u8::MAX,
u8::MAX,
u8::max_value(),
u8::max_value(),
None,
Some(link_id),
max_plaintext_size(),
@@ -994,7 +1008,14 @@ mod fragment_header {
fn fragmented_header_cannot_be_created_with_zero_id() {
assert!(FragmentHeader::try_new(0, 10, 5, None, None).is_err());
assert!(FragmentHeader::try_new(12345, 10, 5, Some(0), None).is_err());
assert!(FragmentHeader::try_new(12345, u8::MAX, u8::MAX, None, Some(0),).is_err());
assert!(FragmentHeader::try_new(
12345,
u8::max_value(),
u8::max_value(),
None,
Some(0),
)
.is_err());
}
#[test]
@@ -1045,7 +1066,14 @@ mod fragment_header {
#[test]
fn can_only_be_post_linked_for_last_fragment() {
assert!(FragmentHeader::try_new(12345, 10, 10, None, Some(1234)).is_ok());
assert!(FragmentHeader::try_new(12345, u8::MAX, u8::MAX, None, Some(1234),).is_ok());
assert!(FragmentHeader::try_new(
12345,
u8::max_value(),
u8::max_value(),
None,
Some(1234),
)
.is_ok());
assert!(FragmentHeader::try_new(12345, 10, 2, Some(1234), None).is_err());
}
@@ -1089,7 +1117,8 @@ mod fragment_header {
#[test]
fn post_linked_can_be_converted_to_and_from_bytes_for_exact_number_of_bytes_provided() {
let fragmented_header =
FragmentHeader::try_new(12345, u8::MAX, u8::MAX, None, Some(1234)).unwrap();
FragmentHeader::try_new(12345, u8::max_value(), u8::max_value(), None, Some(1234))
.unwrap();
let header_bytes = fragmented_header.to_bytes();
let (recovered_header, bytes_used) =
@@ -1101,7 +1130,8 @@ mod fragment_header {
#[test]
fn post_linked_can_be_converted_to_and_from_bytes_for_more_than_required_number_of_bytes() {
let fragmented_header =
FragmentHeader::try_new(12345, u8::MAX, u8::MAX, None, Some(1234)).unwrap();
FragmentHeader::try_new(12345, u8::max_value(), u8::max_value(), None, Some(1234))
.unwrap();
let mut header_bytes = fragmented_header.to_bytes();
header_bytes.append(vec![1, 2, 3, 4, 5].as_mut());
+2 -2
View File
@@ -41,7 +41,7 @@ pub mod set;
/// (or implicitly the only one), it has no lower bound on the number of `Fragment`s.
/// (Apart from the restriction of containing at least a single one). If the set is located
/// somewhere in the middle, *it must be* full. Finally, regardless of its position, it must also be
/// true that it contains no more than `u8::MAX`, i.e. 255 `Fragment`s.
/// true that it contains no more than `u8::max_value()`, i.e. 255 `Fragment`s.
/// Again, the reasoning for this is further explained in `set.rs` file. However, you might
/// also want to look at `fragment.rs` to understand the full context behind that design choice.
///
@@ -151,7 +151,7 @@ mod tests {
- MAX_NODE_ADDRESS_UNPADDED_LEN;
let plaintext_lens = vec![17, used_plaintext_len, 20, 42, 10000];
const SET_LEN: usize = u8::MAX as usize;
const SET_LEN: usize = u8::max_value() as usize;
for plaintext_len in plaintext_lens {
let unlinked_len = unlinked_fragment_payload_max_len(plaintext_len);
+34 -30
View File
@@ -24,7 +24,7 @@ struct ReconstructionBuffer {
previous_fragments_set_id: Option<i32>,
/// Once all fragments are received, the value of `next_fragments_set_id` is copied
/// from the last `Fragment` in the set (assuming the set is full, i.e. it contains
/// `u8::MAX` elements).
/// `u8::max_value()` elements).
next_fragments_set_id: Option<i32>,
/// The actual `Fragment` data held by the `ReconstructionBuffer`. When created it is already
@@ -40,7 +40,7 @@ pub type ReconstructedMessage = (Vec<u8>, Vec<i32>);
impl ReconstructionBuffer {
/// Initialises new instance of a `ReconstructionBuffer` with given size, i.e.
/// number of expected `Fragment`s in the set.
/// The `u8` input type of `size` argument ensures it has the `u8::MAX` upper bound.
/// The `u8` input type of `size` argument ensures it has the `u8::max_value()` upper bound.
fn new(size: u8) -> Self {
// Note: `new` should have never been called with size 0 in the first place
// as `size` value is based on the first recovered `Fragment` in the set.
@@ -122,8 +122,8 @@ impl ReconstructionBuffer {
.as_ref()
.unwrap()
.previous_fragments_set_id();
self.next_fragments_set_id = if self.fragments.len() == u8::MAX as usize {
self.fragments[u8::MAX as usize - 1]
self.next_fragments_set_id = if self.fragments.len() == u8::max_value() as usize {
self.fragments[u8::max_value() as usize - 1]
.as_ref()
.unwrap()
.next_fragments_set_id()
@@ -313,8 +313,8 @@ mod reconstruction_buffer {
assert_eq!(None, frag);
}
let buf = ReconstructionBuffer::new(u8::MAX);
assert_eq!(u8::MAX as usize, buf.fragments.len());
let buf = ReconstructionBuffer::new(u8::max_value());
assert_eq!(u8::max_value() as usize, buf.fragments.len());
for frag in buf.fragments {
assert_eq!(None, frag);
}
@@ -358,11 +358,11 @@ mod reconstruction_buffer {
buf.insert_fragment(Fragment::try_from_bytes(&raw_fragments[2]).unwrap());
assert_eq!(message.to_vec(), buf.reconstruct_set_data());
let mut buf = ReconstructionBuffer::new(u8::MAX);
let mut buf = ReconstructionBuffer::new(u8::max_value());
let message = vec![
42u8;
unlinked_fragment_payload_max_len(AVAILABLE_PLAINTEXT_SIZE)
* u8::MAX as usize
* u8::max_value() as usize
];
let raw_fragments: Vec<_> =
crate::split_into_sets(&mut rand::rngs::OsRng, &message, AVAILABLE_PLAINTEXT_SIZE)
@@ -445,7 +445,7 @@ mod reconstruction_buffer {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize - 1) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize - 1) {
buf.insert_fragment(Fragment::try_from_bytes(raw_fragment).unwrap());
}
@@ -563,7 +563,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -611,7 +611,7 @@ mod message_reconstructor {
.collect();
// note that first set is not fully inserted
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize - 1) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize - 1) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -657,7 +657,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -699,7 +699,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -738,7 +738,7 @@ mod message_reconstructor {
.collect();
// note that first set is not fully inserted
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize - 1) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize - 1) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -779,7 +779,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize * 2) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize * 2) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -793,7 +793,7 @@ mod message_reconstructor {
assert!(reconstructor
.insert_new_fragment(
reconstructor
.recover_fragment(raw_fragments[(u8::MAX as usize) * 2].clone())
.recover_fragment(raw_fragments[(u8::max_value() as usize) * 2].clone())
.unwrap()
)
.is_none());
@@ -822,7 +822,11 @@ mod message_reconstructor {
.collect();
// note that first set is not fully inserted
for raw_fragment in raw_fragments.iter().skip(1).take(u8::MAX as usize * 2 - 1) {
for raw_fragment in raw_fragments
.iter()
.skip(1)
.take(u8::max_value() as usize * 2 - 1)
{
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -835,7 +839,7 @@ mod message_reconstructor {
assert!(reconstructor
.insert_new_fragment(
reconstructor
.recover_fragment(raw_fragments[(u8::MAX as usize) * 2].clone())
.recover_fragment(raw_fragments[(u8::max_value() as usize) * 2].clone())
.unwrap()
)
.is_none());
@@ -892,7 +896,7 @@ mod message_reconstructor {
.collect();
// note that first set is not fully inserted
for raw_fragment in raw_fragments1.iter().take(u8::MAX as usize - 1) {
for raw_fragment in raw_fragments1.iter().take(u8::max_value() as usize - 1) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -926,7 +930,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments2.iter().take(u8::MAX as usize) {
for raw_fragment in raw_fragments2.iter().take(u8::max_value() as usize) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -966,7 +970,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize) {
assert!(reconstructor
.insert_new_fragment(
reconstructor
@@ -1248,7 +1252,7 @@ mod message_reconstructor {
//
// we're inserting this via the buffer approach as not to trigger immediate re-assembly
let mut reconstructor = MessageReconstructor::default();
let mut set_buf1 = ReconstructionBuffer::new(u8::MAX);
let mut set_buf1 = ReconstructionBuffer::new(u8::max_value());
let mut set_buf2 = ReconstructionBuffer::new(1);
let mut rng = thread_rng();
@@ -1263,7 +1267,7 @@ mod message_reconstructor {
.map(|x| x.into_bytes())
.collect();
for raw_fragment in raw_fragments.iter().take(u8::MAX as usize) {
for raw_fragment in raw_fragments.iter().take(u8::max_value() as usize) {
set_buf1.insert_fragment(Fragment::try_from_bytes(raw_fragment).unwrap());
}
@@ -1626,19 +1630,19 @@ mod message_reconstruction {
.into_iter()
.flat_map(|fragment_set| fragment_set.into_iter())
.collect();
assert_eq!(fragments1.len(), u8::MAX as usize);
assert_eq!(fragments1.len(), u8::max_value() as usize);
let mut fragments2: Vec<_> =
crate::split_into_sets(&mut rand::rngs::OsRng, &message2, AVAILABLE_PLAINTEXT_SIZE)
.into_iter()
.flat_map(|fragment_set| fragment_set.into_iter())
.collect();
assert_eq!(fragments2.len(), u8::MAX as usize);
assert_eq!(fragments2.len(), u8::max_value() as usize);
// combine and shuffle fragments
fragments1.append(fragments2.as_mut());
fragments1.shuffle(&mut rng);
let fragments = fragments1;
assert_eq!(fragments.len(), (u8::MAX as usize) * 2);
assert_eq!(fragments.len(), (u8::max_value() as usize) * 2);
let mut message_reconstructor = MessageReconstructor::default();
for fragment in fragments.into_iter() {
@@ -1758,7 +1762,7 @@ mod message_reconstruction {
.flat_map(|fragment_set| fragment_set.into_iter())
.map(|x| x.into_bytes())
.collect();
assert_eq!(fragments.len(), 4 * (u8::MAX as usize));
assert_eq!(fragments.len(), 4 * (u8::max_value() as usize));
// shuffle the fragments
fragments.shuffle(&mut rng);
@@ -1807,19 +1811,19 @@ mod message_reconstruction {
.into_iter()
.flat_map(|fragment_set| fragment_set.into_iter())
.collect();
assert_eq!(fragments1.len(), 4 * (u8::MAX as usize));
assert_eq!(fragments1.len(), 4 * (u8::max_value() as usize));
let mut fragments2: Vec<_> =
crate::split_into_sets(&mut rand::rngs::OsRng, &message2, AVAILABLE_PLAINTEXT_SIZE)
.into_iter()
.flat_map(|fragment_set| fragment_set.into_iter())
.collect();
assert_eq!(fragments2.len(), 4 * (u8::MAX as usize));
assert_eq!(fragments2.len(), 4 * (u8::max_value() as usize));
// combine and shuffle fragments
fragments1.append(fragments2.as_mut());
fragments1.shuffle(&mut rng);
let fragments = fragments1;
assert_eq!(fragments.len(), (u8::MAX as usize) * 8);
assert_eq!(fragments.len(), (u8::max_value() as usize) * 8);
let mut message_reconstructor = MessageReconstructor::default();
for fragment in fragments.into_iter() {
+25 -25
View File
@@ -11,7 +11,7 @@ use rand::Rng;
/// on its payload length of the maximum number of `Fragment`s multiplied by their maximum,
/// fragmented, length.
pub const fn max_unlinked_set_payload_length(max_plaintext_size: usize) -> usize {
u8::MAX as usize * unlinked_fragment_payload_max_len(max_plaintext_size)
u8::max_value() as usize * unlinked_fragment_payload_max_len(max_plaintext_size)
}
/// If the set is being linked to another one, by either being the very first set, or the very last,
@@ -52,8 +52,8 @@ pub const fn two_way_linked_set_payload_length(max_plaintext_size: usize) -> usi
pub(crate) type FragmentSet = Vec<Fragment>;
/// Generate a pseudo-random id for a `FragmentSet`.
/// Its value is restricted to (0, i32::MAX].
/// Note that it *excludes* 0, but *includes* i32::MAX.
/// Its value is restricted to (0, i32::max_value()].
/// Note that it *excludes* 0, but *includes* i32::max_value().
/// This particular range allows for the id to be represented using 31bits, rather than
/// the full length of 32 while still providing more than enough variability to
/// distinguish different `FragmentSet`s.
@@ -89,13 +89,13 @@ fn prepare_unlinked_fragmented_set(
/ unlinked_fragment_payload_max_len(max_plaintext_size) as f64)
.ceil() as usize;
debug_assert!(pre_casted_frags <= u8::MAX as usize);
debug_assert!(pre_casted_frags <= u8::max_value() as usize);
let num_fragments = pre_casted_frags as u8;
let mut fragments = Vec::with_capacity(num_fragments as usize);
for i in 1..(pre_casted_frags + 1) {
// we can't use u8 directly here as upper (NON-INCLUSIVE, so it would always fit) bound could be u8::MAX + 1
// we can't use u8 directly here as upper (NON-INCLUSIVE, so it would always fit) bound could be u8::max_value() + 1
let lb = (i - 1) * unlinked_fragment_payload_max_len(max_plaintext_size);
let ub = usize::min(
message.len(),
@@ -131,7 +131,7 @@ fn prepare_linked_fragment_set(
) -> FragmentSet {
// determine number of fragments in the set:
let num_frags_usize = if next_link_id.is_some() {
u8::MAX as usize
u8::max_value() as usize
} else {
// we know this set is linked, if it's not post-linked then it MUST BE pre-linked
let tail_len = if message.len() >= linked_fragment_payload_max_len(max_plaintext_size) {
@@ -142,7 +142,7 @@ fn prepare_linked_fragment_set(
let pre_casted_frags = 1
+ (tail_len as f64 / unlinked_fragment_payload_max_len(max_plaintext_size) as f64)
.ceil() as usize;
if pre_casted_frags > u8::MAX as usize {
if pre_casted_frags > u8::max_value() as usize {
panic!("message would produce too many fragments!")
};
pre_casted_frags
@@ -162,7 +162,7 @@ fn prepare_linked_fragment_set(
let mut fragments = Vec::with_capacity(num_frags_usize);
for i in 1..(num_frags_usize + 1) {
// we can't use u8 directly here as upper (NON-INCLUSIVE, so i would always fit) bound could be u8::MAX + 1
// we can't use u8 directly here as upper (NON-INCLUSIVE, so i would always fit) bound could be u8::max_value() + 1
let fragment = Fragment::try_new(
&message[lb..ub],
id,
@@ -343,7 +343,7 @@ mod tests {
fn verify_post_linked_set_payload(mut set: FragmentSet, payload: &[u8]) {
for i in (0..set.len()).rev() {
let lb = i * unlinked_fragment_payload_max_len(max_plaintext_size());
let ub = if i == (u8::MAX as usize - 1) {
let ub = if i == (u8::max_value() as usize - 1) {
i * unlinked_fragment_payload_max_len(max_plaintext_size())
+ linked_fragment_payload_max_len(max_plaintext_size())
} else {
@@ -365,7 +365,7 @@ mod tests {
(i - 1) * unlinked_fragment_payload_max_len(max_plaintext_size())
+ linked_fragment_payload_max_len(max_plaintext_size())
};
let ub = if i == (u8::MAX as usize - 1) {
let ub = if i == (u8::max_value() as usize - 1) {
(i - 1) * unlinked_fragment_payload_max_len(max_plaintext_size())
+ 2 * linked_fragment_payload_max_len(max_plaintext_size())
} else {
@@ -434,7 +434,7 @@ mod tests {
id,
max_plaintext_size(),
);
assert_eq!(u8::MAX as usize, max_fragment_set.len());
assert_eq!(u8::max_value() as usize, max_fragment_set.len());
verify_unlinked_set_payload(max_fragment_set, &max_fragments_set_payload);
let mut full_set_payload =
@@ -442,7 +442,7 @@ mod tests {
rng.fill_bytes(&mut full_set_payload);
let full_fragment_set =
prepare_unlinked_fragmented_set(&full_set_payload, id, max_plaintext_size());
assert_eq!(u8::MAX as usize, full_fragment_set.len());
assert_eq!(u8::max_value() as usize, full_fragment_set.len());
verify_unlinked_set_payload(full_fragment_set, &full_set_payload);
}
@@ -515,7 +515,7 @@ mod tests {
None,
max_plaintext_size(),
);
assert_eq!(u8::MAX as usize, max_fragment_set.len());
assert_eq!(u8::max_value() as usize, max_fragment_set.len());
verify_pre_linked_set_payload(max_fragment_set, &max_fragments_set_payload);
let mut full_set_payload =
@@ -528,7 +528,7 @@ mod tests {
None,
max_plaintext_size(),
);
assert_eq!(u8::MAX as usize, full_fragment_set.len());
assert_eq!(u8::max_value() as usize, full_fragment_set.len());
verify_pre_linked_set_payload(full_fragment_set, &full_set_payload);
}
@@ -561,7 +561,7 @@ mod tests {
Some(link_id),
max_plaintext_size(),
);
assert_eq!(u8::MAX as usize, full_fragment_set.len());
assert_eq!(u8::max_value() as usize, full_fragment_set.len());
verify_post_linked_set_payload(full_fragment_set, &full_set_payload);
}
@@ -608,7 +608,7 @@ mod tests {
Some(post_link_id),
max_plaintext_size(),
);
assert_eq!(u8::MAX as usize, full_fragment_set.len());
assert_eq!(u8::max_value() as usize, full_fragment_set.len());
verify_two_way_linked_set_payload(full_fragment_set, &full_set_payload);
}
@@ -700,8 +700,8 @@ mod tests {
let mut sets = split_into_sets(&mut rng, &message, max_plaintext_size());
assert_eq!(2, sets.len());
assert_eq!(sets[0].len(), u8::MAX as usize);
assert_eq!(sets[1].len(), u8::MAX as usize);
assert_eq!(sets[0].len(), u8::max_value() as usize);
assert_eq!(sets[1].len(), u8::max_value() as usize);
verify_correct_link(&sets[0], &sets[1]);
verify_pre_linked_set_payload(
sets.pop().unwrap(),
@@ -726,9 +726,9 @@ mod tests {
rng.fill_bytes(&mut message);
let mut sets = split_into_sets(&mut rng, &message, max_plaintext_size());
assert_eq!(4, sets.len());
assert_eq!(sets[0].len(), u8::MAX as usize);
assert_eq!(sets[1].len(), u8::MAX as usize);
assert_eq!(sets[2].len(), u8::MAX as usize);
assert_eq!(sets[0].len(), u8::max_value() as usize);
assert_eq!(sets[1].len(), u8::max_value() as usize);
assert_eq!(sets[2].len(), u8::max_value() as usize);
verify_correct_link(&sets[0], &sets[1]);
verify_correct_link(&sets[1], &sets[2]);
@@ -766,10 +766,10 @@ mod tests {
let mut sets = split_into_sets(&mut rng, &message, max_plaintext_size());
assert_eq!(4, sets.len());
assert_eq!(sets[0].len(), u8::MAX as usize);
assert_eq!(sets[1].len(), u8::MAX as usize);
assert_eq!(sets[2].len(), u8::MAX as usize);
assert_eq!(sets[3].len(), u8::MAX as usize);
assert_eq!(sets[0].len(), u8::max_value() as usize);
assert_eq!(sets[1].len(), u8::max_value() as usize);
assert_eq!(sets[2].len(), u8::max_value() as usize);
assert_eq!(sets[3].len(), u8::max_value() as usize);
verify_correct_link(&sets[0], &sets[1]);
verify_correct_link(&sets[1], &sets[2]);
+4 -4
View File
@@ -235,7 +235,7 @@ mod message_receiver {
1,
vec![mix::Node {
mix_id: 123,
owner: None,
owner: "foomp1".to_string(),
host: "10.20.30.40".parse().unwrap(),
mix_host: "10.20.30.40:1789".parse().unwrap(),
identity_key: identity::PublicKey::from_base58_string(
@@ -255,7 +255,7 @@ mod message_receiver {
2,
vec![mix::Node {
mix_id: 234,
owner: None,
owner: "foomp2".to_string(),
host: "11.21.31.41".parse().unwrap(),
mix_host: "11.21.31.41:1789".parse().unwrap(),
identity_key: identity::PublicKey::from_base58_string(
@@ -275,7 +275,7 @@ mod message_receiver {
3,
vec![mix::Node {
mix_id: 456,
owner: None,
owner: "foomp3".to_string(),
host: "12.22.32.42".parse().unwrap(),
mix_host: "12.22.32.42:1789".parse().unwrap(),
identity_key: identity::PublicKey::from_base58_string(
@@ -295,7 +295,7 @@ mod message_receiver {
// currently coco_nodes don't really exist so this is still to be determined
mixes,
vec![gateway::Node {
owner: None,
owner: "foomp4".to_string(),
host: "1.2.3.4".parse().unwrap(),
mix_host: "1.2.3.4:1789".parse().unwrap(),
clients_ws_port: 9000,
+9 -52
View File
@@ -8,9 +8,6 @@ use nym_mixnet_contract_common::GatewayBond;
use nym_sphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
use nym_sphinx_types::Node as SphinxNode;
use nym_api_requests::nym_nodes::SkimmedNode;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::fmt;
use std::fmt::Formatter;
use std::io;
@@ -43,13 +40,11 @@ pub enum GatewayConversionError {
#[source]
err: AddrParseError,
},
#[error("provided node is not an entry gateway in this epoch!")]
NotGateway,
}
#[derive(Clone)]
pub struct Node {
pub owner: String,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
@@ -63,9 +58,6 @@ pub struct Node {
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
// to be removed:
pub owner: Option<String>,
pub version: NodeVersion,
}
@@ -86,9 +78,11 @@ impl std::fmt::Debug for Node {
impl Node {
pub fn parse_host(raw: &str) -> Result<NetworkAddress, GatewayConversionError> {
// safety: this conversion is infallible
// (but we retain result return type for legacy reasons)
Ok(raw.parse().unwrap())
raw.parse()
.map_err(|err| GatewayConversionError::InvalidAddress {
value: raw.to_owned(),
source: err,
})
}
pub fn extract_mix_host(
@@ -126,7 +120,7 @@ impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Node(id: {}, owner: {:?}, host: {})",
"Node(id: {}, owner: {}, host: {})",
self.identity_key, self.owner, self.host,
)
}
@@ -160,7 +154,7 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
let mix_host = Self::extract_mix_host(&host, bond.gateway.mix_port)?;
Ok(Node {
owner: Some(bond.owner.as_str().to_owned()),
owner: bond.owner.as_str().to_owned(),
host,
mix_host,
clients_ws_port: bond.gateway.clients_port,
@@ -205,7 +199,7 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {
let mix_host = SocketAddr::new(ips[0], value.bond.gateway.mix_port);
Ok(Node {
owner: Some(value.bond.owner.as_str().to_owned()),
owner: value.bond.owner.as_str().to_owned(),
host,
mix_host,
clients_ws_port: self_described.mixnet_websockets.ws_port,
@@ -225,43 +219,6 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {
}
}
impl<'a> TryFrom<&'a SkimmedNode> for Node {
type Error = GatewayConversionError;
fn try_from(value: &'a SkimmedNode) -> Result<Self, Self::Error> {
let Some(entry_details) = &value.entry else {
return Err(GatewayConversionError::NotGateway);
};
if value.ip_addresses.is_empty() {
return Err(GatewayConversionError::NoIpAddressesProvided {
gateway: value.ed25519_identity_pubkey.clone(),
});
}
// safety: we just checked the slice is not empty
#[allow(clippy::unwrap_used)]
let ip = value.ip_addresses.choose(&mut thread_rng()).unwrap();
let host = if let Some(hostname) = &entry_details.hostname {
NetworkAddress::Hostname(hostname.to_string())
} else {
NetworkAddress::IpAddr(*ip)
};
Ok(Node {
host,
mix_host: SocketAddr::new(*ip, value.mix_port),
clients_ws_port: entry_details.ws_port,
clients_wss_port: entry_details.wss_port,
identity_key: value.ed25519_identity_pubkey.parse()?,
sphinx_key: value.x25519_sphinx_pubkey.parse()?,
owner: None,
version: NodeVersion::Unknown,
})
}
}
impl TryFrom<DescribedGateway> for Node {
type Error = GatewayConversionError;
+6 -41
View File
@@ -6,7 +6,7 @@
use crate::filter::VersionFilterable;
pub use error::NymTopologyError;
use log::{debug, warn};
use log::warn;
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_sphinx_addressing::nodes::NodeIdentity;
@@ -14,7 +14,6 @@ use nym_sphinx_types::Node as SphinxNode;
use rand::prelude::SliceRandom;
use rand::{CryptoRng, Rng};
use std::collections::BTreeMap;
use std::convert::Infallible;
use std::fmt::{self, Display, Formatter};
use std::io;
@@ -94,7 +93,7 @@ impl NetworkAddress {
}
impl FromStr for NetworkAddress {
type Err = Infallible;
type Err = std::io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(ip_addr) = s.parse() {
@@ -138,38 +137,6 @@ impl NymTopology {
NymTopology { mixes, gateways }
}
pub fn from_unordered<MI, GI, M, G>(unordered_mixes: MI, unordered_gateways: GI) -> Self
where
MI: Iterator<Item = M>,
GI: Iterator<Item = G>,
G: TryInto<gateway::Node>,
M: TryInto<mix::Node>,
<G as TryInto<gateway::Node>>::Error: Display,
<M as TryInto<mix::Node>>::Error: Display,
{
let mut mixes = BTreeMap::new();
let mut gateways = Vec::new();
for node in unordered_mixes.into_iter() {
match node.try_into() {
Ok(mixnode) => mixes
.entry(mixnode.layer as MixLayer)
.or_insert_with(Vec::new)
.push(mixnode),
Err(err) => debug!("malformed mixnode: {err}"),
}
}
for node in unordered_gateways.into_iter() {
match node.try_into() {
Ok(gateway) => gateways.push(gateway),
Err(err) => debug!("malformed gateway: {err}"),
}
}
NymTopology::new(mixes, gateways)
}
#[cfg(feature = "serializable")]
pub fn new_from_file<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<Self> {
let file = std::fs::File::open(path)?;
@@ -524,7 +491,7 @@ mod converting_mixes_to_vec {
fn returns_a_vec_with_hashmap_values() {
let node1 = mix::Node {
mix_id: 42,
owner: Some("N/A".to_string()),
owner: "N/A".to_string(),
host: "3.3.3.3".parse().unwrap(),
mix_host: "3.3.3.3:1789".parse().unwrap(),
identity_key: identity::PublicKey::from_base58_string(
@@ -540,12 +507,12 @@ mod converting_mixes_to_vec {
};
let node2 = mix::Node {
owner: Some("Alice".to_string()),
owner: "Alice".to_string(),
..node1.clone()
};
let node3 = mix::Node {
owner: Some("Bob".to_string()),
owner: "Bob".to_string(),
..node1.clone()
};
@@ -555,9 +522,7 @@ mod converting_mixes_to_vec {
let topology = NymTopology::new(mixes, vec![]);
let mixvec = topology.mixes_as_vec();
assert!(mixvec
.iter()
.any(|node| node.owner.as_ref() == Some(&"N/A".to_string())));
assert!(mixvec.iter().any(|node| node.owner == "N/A"));
}
}
+7 -55
View File
@@ -8,9 +8,6 @@ use nym_mixnet_contract_common::{MixId, MixNodeBond};
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx_types::Node as SphinxNode;
use nym_api_requests::nym_nodes::{NodeRole, SkimmedNode};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::fmt::Formatter;
use std::io;
use std::net::SocketAddr;
@@ -30,20 +27,12 @@ pub enum MixnodeConversionError {
#[source]
source: io::Error,
},
#[error("invalid mix layer")]
InvalidLayer,
#[error("'{mixnode}' has not provided any valid ip addresses")]
NoIpAddressesProvided { mixnode: String },
#[error("provided node is not a mixnode in this epoch!")]
NotMixnode,
}
#[derive(Clone)]
pub struct Node {
pub mix_id: MixId,
pub owner: String,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
@@ -51,10 +40,7 @@ pub struct Node {
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub layer: Layer,
// to be removed:
pub version: NodeVersion,
pub owner: Option<String>,
}
impl std::fmt::Debug for Node {
@@ -74,9 +60,11 @@ impl std::fmt::Debug for Node {
impl Node {
pub fn parse_host(raw: &str) -> Result<NetworkAddress, MixnodeConversionError> {
// safety: this conversion is infallible
// (but we retain result return type for legacy reasons)
Ok(raw.parse().unwrap())
raw.parse()
.map_err(|err| MixnodeConversionError::InvalidAddress {
value: raw.to_owned(),
source: err,
})
}
pub fn extract_mix_host(
@@ -121,7 +109,7 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
Ok(Node {
mix_id: bond.mix_id,
owner: Some(bond.owner.as_str().to_owned()),
owner: bond.owner.as_str().to_owned(),
host,
mix_host,
identity_key: identity::PublicKey::from_base58_string(&bond.mix_node.identity_key)?,
@@ -132,42 +120,6 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
}
}
impl<'a> TryFrom<&'a SkimmedNode> for Node {
type Error = MixnodeConversionError;
fn try_from(value: &'a SkimmedNode) -> Result<Self, Self::Error> {
if value.ip_addresses.is_empty() {
return Err(MixnodeConversionError::NoIpAddressesProvided {
mixnode: value.ed25519_identity_pubkey.clone(),
});
}
let layer = match value.role {
NodeRole::Mixnode { layer } => layer
.try_into()
.map_err(|_| MixnodeConversionError::InvalidLayer)?,
_ => return Err(MixnodeConversionError::NotMixnode),
};
// safety: we just checked the slice is not empty
#[allow(clippy::unwrap_used)]
let ip = value.ip_addresses.choose(&mut thread_rng()).unwrap();
let host = NetworkAddress::IpAddr(*ip);
Ok(Node {
mix_id: value.node_id,
host,
mix_host: SocketAddr::new(*ip, value.mix_port),
identity_key: value.ed25519_identity_pubkey.parse()?,
sphinx_key: value.x25519_sphinx_pubkey.parse()?,
layer,
owner: None,
version: NodeVersion::Unknown,
})
}
}
impl TryFrom<MixNodeBond> for Node {
type Error = MixnodeConversionError;
+2 -4
View File
@@ -109,8 +109,7 @@ pub struct SerializableMixNode {
#[serde(alias = "mix_id")]
pub mix_id: u32,
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
pub owner: Option<String>,
pub owner: String,
pub host: String,
@@ -181,8 +180,7 @@ impl<'a> From<&'a mix::Node> for SerializableMixNode {
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct SerializableGateway {
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
pub owner: Option<String>,
pub owner: String,
pub host: String,
-12
View File
@@ -362,14 +362,6 @@ pub struct TopologyWasm {
/// the first valid instance.
/// Supersedes `topology_refresh_rate_ms`.
pub disable_refreshing: bool,
/// Specifies a minimum performance of a mixnode that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_mixnode_performance: u8,
/// Specifies a minimum performance of a gateway that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_gateway_performance: u8,
}
impl Default for TopologyWasm {
@@ -390,8 +382,6 @@ impl From<TopologyWasm> for ConfigTopology {
topology.max_startup_gateway_waiting_period_ms as u64,
),
topology_structure: Default::default(),
minimum_mixnode_performance: topology.minimum_mixnode_performance,
minimum_gateway_performance: topology.minimum_gateway_performance,
}
}
}
@@ -405,8 +395,6 @@ impl From<ConfigTopology> for TopologyWasm {
.max_startup_gateway_waiting_period
.as_millis() as u32,
disable_refreshing: topology.disable_refreshing,
minimum_mixnode_performance: topology.minimum_mixnode_performance,
minimum_gateway_performance: topology.minimum_gateway_performance,
}
}
}
@@ -244,16 +244,6 @@ pub struct TopologyWasmOverride {
/// Supersedes `topology_refresh_rate_ms`.
#[tsify(optional)]
pub disable_refreshing: Option<bool>,
/// Specifies a minimum performance of a mixnode that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
#[tsify(optional)]
pub minimum_mixnode_performance: Option<u8>,
/// Specifies a minimum performance of a gateway that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
#[tsify(optional)]
pub minimum_gateway_performance: Option<u8>,
}
impl From<TopologyWasmOverride> for TopologyWasm {
@@ -271,12 +261,6 @@ impl From<TopologyWasmOverride> for TopologyWasm {
.max_startup_gateway_waiting_period_ms
.unwrap_or(def.max_startup_gateway_waiting_period_ms),
disable_refreshing: value.disable_refreshing.unwrap_or(def.disable_refreshing),
minimum_mixnode_performance: value
.minimum_mixnode_performance
.unwrap_or(def.minimum_mixnode_performance),
minimum_gateway_performance: value
.minimum_gateway_performance
.unwrap_or(def.minimum_gateway_performance),
}
}
}
+1 -1
View File
@@ -122,7 +122,7 @@ pub async fn setup_gateway_from_api(
nym_apis: &[Url],
) -> Result<InitialisationResult, WasmCoreError> {
let mut rng = thread_rng();
let gateways = current_gateways(&mut rng, nym_apis, None).await?;
let gateways = current_gateways(&mut rng, nym_apis).await?;
setup_gateway_wasm(client_store, force_tls, chosen_gateway, &gateways).await
}
+2 -5
View File
@@ -16,7 +16,7 @@ pub struct WasmRawRegisteredGateway {
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
pub gateway_owner_address: Option<String>,
pub gateway_owner_address: String,
pub gateway_listener: String,
}
@@ -55,10 +55,7 @@ impl<'a> From<&'a GatewayRegistration> for WasmRawRegisteredGateway {
derived_aes128_ctr_blake3_hmac_keys_bs58: remote_details
.derived_aes128_ctr_blake3_hmac_keys
.to_base58_string(),
gateway_owner_address: remote_details
.gateway_owner_address
.as_ref()
.map(|a| a.to_string()),
gateway_owner_address: remote_details.gateway_owner_address.to_string(),
gateway_listener: remote_details.gateway_listener.to_string(),
}
}
-1
View File
@@ -25,4 +25,3 @@ nym-network-defaults = { path = "../network-defaults" }
nym-task = { path = "../task" }
nym-wireguard-types = { path = "../wireguard-types" }
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
tokio-stream = { workspace = true }
+3 -45
View File
@@ -1,24 +1,13 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::{
sync::Arc,
time::{Duration, SystemTime},
};
use std::sync::Arc;
use defguard_wireguard_rs::{
host::{Host, Peer},
key::Key,
WGApi, WireguardInterfaceApi,
};
use defguard_wireguard_rs::{host::Peer, key::Key, WireguardInterfaceApi};
use tokio::sync::mpsc;
use tokio_stream::{wrappers::IntervalStream, StreamExt};
use crate::WgApiWrapper;
const DEFAULT_PEER_TIMEOUT: Duration = Duration::from_secs(60 * 60); // 1 hour
const DEFAULT_PEER_TIMEOUT_CHECK: Duration = Duration::from_secs(60); // 1 minute
pub enum PeerControlMessage {
AddPeer(Peer),
RemovePeer(Key),
@@ -27,7 +16,6 @@ pub enum PeerControlMessage {
pub struct PeerController {
peer_rx: mpsc::UnboundedReceiver<PeerControlMessage>,
wg_api: Arc<WgApiWrapper>,
timeout_check_interval: IntervalStream,
}
impl PeerController {
@@ -35,42 +23,12 @@ impl PeerController {
wg_api: Arc<WgApiWrapper>,
peer_rx: mpsc::UnboundedReceiver<PeerControlMessage>,
) -> Self {
let timeout_check_interval = tokio_stream::wrappers::IntervalStream::new(
tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK),
);
PeerController {
wg_api,
peer_rx,
timeout_check_interval,
}
}
fn remove_stale_peers(wg_api: &WGApi, host: Host) {
let current_timestamp = SystemTime::now();
for (key, peer) in host.peers.iter() {
if let Some(timestamp) = peer.last_handshake {
if let Ok(duration_since_handshake) = current_timestamp.duration_since(timestamp) {
if duration_since_handshake > DEFAULT_PEER_TIMEOUT {
if let Err(e) = wg_api.remove_peer(key) {
log::error!("Could not remove stale peer: {:?}", e);
} else {
log::debug!("Removed stale peer {:?}", key);
}
}
}
}
}
PeerController { wg_api, peer_rx }
}
pub async fn run(&mut self, mut task_client: nym_task::TaskClient) {
loop {
tokio::select! {
_ = self.timeout_check_interval.next() => {
match self.wg_api.inner.read_interface_data() {
Ok(host) => Self::remove_stale_peers(&self.wg_api.inner, host),
Err(e) => { log::error!("Could not read peer data: {:?}", e); },
}
}
_ = task_client.recv() => {
log::trace!("PeerController handler: Received shutdown");
break;
+188 -51
View File
@@ -81,6 +81,12 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake2"
version = "0.8.1"
@@ -151,35 +157,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "camino"
version = "1.1.7"
name = "cc"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
dependencies = [
"serde",
]
[[package]]
name = "cargo-platform"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror",
"jobserver",
"libc",
]
[[package]]
@@ -574,7 +558,6 @@ dependencies = [
"cw3-fixed-multisig",
"cw4",
"cw4-group",
"nym-contracts-common",
"nym-group-contract-common",
"nym-multisig-contract-common",
]
@@ -603,7 +586,6 @@ dependencies = [
"cw-utils",
"cw2",
"cw4",
"nym-contracts-common",
"nym-group-contract-common",
"schemars",
"serde",
@@ -797,6 +779,26 @@ dependencies = [
"zeroize",
]
[[package]]
name = "enum-iterator"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a0ac4aeb3a18f92eaf09c6bb9b3ac30ff61ca95514fc58cbead1c9a6bf5401"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.59",
]
[[package]]
name = "ff"
version = "0.12.1"
@@ -823,6 +825,15 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
[[package]]
name = "forward_ref"
version = "1.0.0"
@@ -860,6 +871,31 @@ dependencies = [
"wasi",
]
[[package]]
name = "getset"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "git2"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c"
dependencies = [
"bitflags",
"libc",
"libgit2-sys",
"log",
"url",
]
[[package]]
name = "group"
version = "0.12.1"
@@ -931,6 +967,16 @@ dependencies = [
"serde",
]
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "inout"
version = "0.1.3"
@@ -955,6 +1001,15 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jobserver"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2"
dependencies = [
"libc",
]
[[package]]
name = "k256"
version = "0.11.6"
@@ -993,12 +1048,36 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libgit2-sys"
version = "0.13.5+1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51e5ea06c26926f1002dd553fded6cfcdc9784c1f60feeb58368b4d9b07b6dba"
dependencies = [
"cc",
"libc",
"libz-sys",
"pkg-config",
]
[[package]]
name = "libm"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "libz-sys"
version = "1.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "lioness"
version = "0.1.2"
@@ -1055,15 +1134,6 @@ dependencies = [
"libm",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "nym-coconut-bandwidth"
version = "0.1.0"
@@ -1103,8 +1173,8 @@ dependencies = [
"cw4",
"cw4-group",
"nym-coconut-dkg-common",
"nym-contracts-common",
"nym-group-contract-common",
"semver",
"serde",
"thiserror",
]
@@ -1129,11 +1199,9 @@ dependencies = [
"bs58 0.5.1",
"cosmwasm-schema",
"cosmwasm-std",
"cw-storage-plus",
"schemars",
"serde",
"thiserror",
"vergen",
]
[[package]]
@@ -1178,9 +1246,11 @@ dependencies = [
"nym-mixnet-contract-common",
"nym-vesting-contract-common",
"rand_chacha",
"semver",
"serde",
"thiserror",
"time",
"vergen",
]
[[package]]
@@ -1248,9 +1318,11 @@ dependencies = [
"nym-mixnet-contract-common",
"nym-vesting-contract-common",
"rand_chacha",
"semver",
"serde",
"serde_json",
"thiserror",
"vergen",
]
[[package]]
@@ -1295,6 +1367,12 @@ dependencies = [
"regex",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pkcs8"
version = "0.9.0"
@@ -1315,6 +1393,12 @@ dependencies = [
"spki 0.7.3",
]
[[package]]
name = "pkg-config"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "platforms"
version = "3.4.0"
@@ -1333,6 +1417,30 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.81"
@@ -1548,9 +1656,6 @@ name = "semver"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
dependencies = [
"serde",
]
[[package]]
name = "serde"
@@ -1774,9 +1879,7 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
@@ -1820,6 +1923,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-bidi"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-ident"
version = "1.0.12"
@@ -1827,17 +1936,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "vergen"
version = "8.3.1"
name = "unicode-normalization"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525"
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
dependencies = [
"tinyvec",
]
[[package]]
name = "url"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vergen"
version = "7.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447f9238a4553957277b3ee09d80babeae0811f1b3baefb093de1c0448437a37"
dependencies = [
"anyhow",
"cargo_metadata",
"cfg-if",
"regex",
"enum-iterator",
"getset",
"git2",
"rustc_version",
"rustversion",
"thiserror",
"time",
]
+1 -1
View File
@@ -14,7 +14,6 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
nym-coconut-dkg-common = { path = "../../common/cosmwasm-smart-contracts/coconut-dkg" }
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" }
cosmwasm-schema = { workspace = true, optional = true }
cosmwasm-std = { workspace = true }
@@ -24,6 +23,7 @@ cw-controllers = { workspace = true }
cw2 = { workspace = true }
cw4 = { workspace = true }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
semver = { workspace = true, default-features = false }
thiserror = { workspace = true }
[dev-dependencies]
+20 -4
View File
@@ -30,7 +30,7 @@ use cosmwasm_std::{
use cw4::Cw4Contract;
use nym_coconut_dkg_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use nym_coconut_dkg_common::types::{Epoch, EpochState, State};
use nym_contracts_common::set_build_information;
use semver::Version;
const CONTRACT_NAME: &str = "crate:nym-coconut-dkg";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -77,7 +77,6 @@ pub fn instantiate(
)?;
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
set_build_information!(deps.storage)?;
Ok(Response::default())
}
@@ -214,8 +213,25 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
#[entry_point]
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
set_build_information!(deps.storage)?;
cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
fn parse_semver(raw: &str) -> Result<Version, ContractError> {
raw.parse()
.map_err(|error: semver::Error| ContractError::SemVerFailure {
value: CONTRACT_VERSION.to_string(),
error_message: error.to_string(),
})
}
// Note: don't remove this particular bit of code as we have to ALWAYS check whether we have to
// update the stored version
let build_version: Version = parse_semver(CONTRACT_VERSION)?;
let stored_version: Version = parse_semver(&cw2::get_contract_version(deps.storage)?.version)?;
if stored_version < build_version {
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
// If state structure changed in any contract version in the way migration is needed, it
// should occur here, for example anything from `crate::queued_migrations::`
}
Ok(Response::new())
}
+6
View File
@@ -128,6 +128,12 @@ pub enum ContractError {
#[error("No verification key committed for owner {owner}")]
NoCommitForOwner { owner: String },
#[error("failed to parse {value} into a valid SemVer version: {error_message}")]
SemVerFailure {
value: String,
error_message: String,
},
#[error("cannot perform DKG reset during an ongoing exchange")]
CantResetDuringExchange,
+5
View File
@@ -0,0 +1,5 @@
[alias]
wasm = "build --release --lib --target wasm32-unknown-unknown"
wasm-debug = "build --target wasm32-unknown-unknown"
unit-test = "test --lib"
schema = "run --bin schema --features=schema-gen"
+36
View File
@@ -0,0 +1,36 @@
[package]
name = "nym-ephemera"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "schema"
required-features = ["schema-gen"]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
nym-ephemera-common = { path = "../../common/cosmwasm-smart-contracts/ephemera" }
cosmwasm-schema = { workspace = true, optional = true }
cosmwasm-std = { workspace = true }
cosmwasm-storage = { workspace = true }
cw-storage-plus = { workspace = true }
cw-controllers = { workspace = true }
cw4 = { workspace = true }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { workspace = true }
[dev-dependencies]
cw-multi-test = { workspace = true }
cw4-group = { path = "../multisig/cw4-group" }
nym-group-contract-common = { path = "../../common/cosmwasm-smart-contracts/group-contract" }
lazy_static = "1.4"
rusty-fork = "0.3"
[features]
schema-gen = ["nym-ephemera-common/schema", "cosmwasm-schema"]
+2
View File
@@ -0,0 +1,2 @@
generate-schema:
cargo schema
+194
View File
@@ -0,0 +1,194 @@
{
"contract_name": "nym-ephemera",
"contract_version": "0.1.0",
"idl_version": "1.0.0",
"instantiate": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InstantiateMsg",
"type": "object",
"required": [
"group_addr",
"mix_denom"
],
"properties": {
"group_addr": {
"type": "string"
},
"mix_denom": {
"type": "string"
}
},
"additionalProperties": false
},
"execute": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"oneOf": [
{
"type": "object",
"required": [
"register_peer"
],
"properties": {
"register_peer": {
"type": "object",
"required": [
"peer_info"
],
"properties": {
"peer_info": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
},
"query": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "QueryMsg",
"oneOf": [
{
"type": "object",
"required": [
"get_peers"
],
"properties": {
"get_peers": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
},
"migrate": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"additionalProperties": false
},
"sudo": null,
"responses": {
"get_peers": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedPeerResponse",
"type": "object",
"required": [
"peers",
"per_page"
],
"properties": {
"peers": {
"type": "array",
"items": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"per_page": {
"type": "integer",
"format": "uint",
"minimum": 0.0
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"anyOf": [
{
"$ref": "#/definitions/Addr"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
}
}
}
@@ -0,0 +1,60 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"oneOf": [
{
"type": "object",
"required": [
"register_peer"
],
"properties": {
"register_peer": {
"type": "object",
"required": [
"peer_info"
],
"properties": {
"peer_info": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
}
@@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InstantiateMsg",
"type": "object",
"required": [
"group_addr",
"mix_denom"
],
"properties": {
"group_addr": {
"type": "string"
},
"mix_denom": {
"type": "string"
}
},
"additionalProperties": false
}
@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"additionalProperties": false
}
+35
View File
@@ -0,0 +1,35 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "QueryMsg",
"oneOf": [
{
"type": "object",
"required": [
"get_peers"
],
"properties": {
"get_peers": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
}
@@ -0,0 +1,67 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedPeerResponse",
"type": "object",
"required": [
"peers",
"per_page"
],
"properties": {
"peers": {
"type": "array",
"items": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"per_page": {
"type": "integer",
"format": "uint",
"minimum": 0.0
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"anyOf": [
{
"$ref": "#/definitions/Addr"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::write_api;
use nym_ephemera_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
fn main() {
write_api! {
instantiate: InstantiateMsg,
query: QueryMsg,
execute: ExecuteMsg,
migrate: MigrateMsg,
}
}
+97
View File
@@ -0,0 +1,97 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::ContractError;
use crate::peers::queries::query_peers_paged;
use crate::peers::transactions::try_register_peer;
use crate::state::{State, STATE};
use cosmwasm_std::{
entry_point, to_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
};
use cw4::Cw4Contract;
use nym_ephemera_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
/// Instantiate the contract.
///
/// `deps` contains Storage, API and Querier
/// `env` contains block, message and contract info
/// `msg` is the contract initialization message, sort of like a constructor call.
#[entry_point]
pub fn instantiate(
deps: DepsMut<'_>,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
let group_addr = Cw4Contract(deps.api.addr_validate(&msg.group_addr).map_err(|_| {
ContractError::InvalidGroup {
addr: msg.group_addr.clone(),
}
})?);
let state = State {
group_addr,
mix_denom: msg.mix_denom,
};
STATE.save(deps.storage, &state)?;
Ok(Response::default())
}
/// Handle an incoming message
#[entry_point]
pub fn execute(
deps: DepsMut<'_>,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::RegisterPeer { peer_info } => try_register_peer(deps, info, peer_info),
}
}
#[entry_point]
pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
let response = match msg {
QueryMsg::GetPeers { limit, start_after } => {
to_binary(&query_peers_paged(deps, start_after, limit)?)?
}
};
Ok(response)
}
#[entry_point]
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Default::default())
}
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::Addr;
#[test]
fn initialize_contract() {
let mut deps = mock_dependencies();
let env = mock_env();
let init_msg = InstantiateMsg {
group_addr: "group_addr".to_string(),
mix_denom: "uatom".to_string(),
};
let sender = mock_info("sender", &[]);
let res = instantiate(deps.as_mut(), env, sender, init_msg);
assert!(res.is_ok());
let expected_state = State {
group_addr: Cw4Contract::new(Addr::unchecked("group_addr")),
mix_denom: "uatom".to_string(),
};
let state = STATE.load(deps.as_ref().storage).unwrap();
assert_eq!(state, expected_state);
}
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::StdError;
use thiserror::Error;
/// Custom errors for contract failure conditions.
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error(transparent)]
Std(#[from] StdError),
#[error("Group contract invalid address '{addr}'")]
InvalidGroup { addr: String },
#[error("This potential ephemera peer is not in the ephemera group")]
Unauthorized,
#[error("This sender is already registered")]
AlreadyRegistered,
}
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod contract;
pub mod error;
mod peers;
mod state;
mod support;
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod queries;
pub mod storage;
pub mod transactions;
+164
View File
@@ -0,0 +1,164 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::peers::storage::{PEERS, PEERS_PAGE_DEFAULT_LIMIT, PEERS_PAGE_MAX_LIMIT};
use cosmwasm_std::{Deps, Order, StdResult};
use cw_storage_plus::Bound;
use nym_ephemera_common::peers::PagedPeerResponse;
pub fn query_peers_paged(
deps: Deps<'_>,
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<PagedPeerResponse> {
let limit = limit
.unwrap_or(PEERS_PAGE_DEFAULT_LIMIT)
.min(PEERS_PAGE_MAX_LIMIT) as usize;
let addr = start_after
.map(|addr| deps.api.addr_validate(&addr))
.transpose()?;
let start = addr.map(Bound::exclusive);
let peers = PEERS
.range(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|res| res.map(|item| item.1))
.collect::<StdResult<Vec<_>>>()?;
let start_next_after = peers
.last()
.map(|peer_info| peer_info.cosmos_address.clone());
Ok(PagedPeerResponse::new(peers, limit, start_next_after))
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::peers::storage::{PEERS_PAGE_DEFAULT_LIMIT, PEERS_PAGE_MAX_LIMIT};
use crate::support::tests::fixtures::peer_fixture;
use crate::support::tests::helpers::init_contract;
use cosmwasm_std::DepsMut;
fn fill_peers(deps: DepsMut<'_>, size: usize) {
for n in 0..size {
let peer = peer_fixture(&format!("peer{}", n));
PEERS
.save(deps.storage, peer.cosmos_address.clone(), &peer)
.unwrap();
}
}
fn remove_peers(deps: DepsMut<'_>, size: usize) {
for n in 0..size {
let peer = peer_fixture(&format!("peer{}", n));
PEERS.remove(deps.storage, peer.cosmos_address);
}
}
#[test]
fn peers_empty_on_init() {
let deps = init_contract();
let page1 = query_peers_paged(deps.as_ref(), None, None).unwrap();
assert_eq!(0, page1.peers.len() as u32);
}
#[test]
fn peers_paged_retrieval_obeys_limits() {
let mut deps = init_contract();
let limit = 2;
fill_peers(deps.as_mut(), 1000);
let page1 = query_peers_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
assert_eq!(limit, page1.peers.len() as u32);
remove_peers(deps.as_mut(), 1000);
}
#[test]
fn peers_paged_retrieval_has_default_limit() {
let mut deps = init_contract();
fill_peers(deps.as_mut(), 1000);
// query without explicitly setting a limit
let page1 = query_peers_paged(deps.as_ref(), None, None).unwrap();
assert_eq!(PEERS_PAGE_DEFAULT_LIMIT, page1.peers.len() as u32);
remove_peers(deps.as_mut(), 1000);
}
#[test]
fn peers_paged_retrieval_has_max_limit() {
let mut deps = init_contract();
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000 * PEERS_PAGE_MAX_LIMIT;
fill_peers(deps.as_mut(), 1000);
let page1 = query_peers_paged(deps.as_ref(), None, Option::from(crazy_limit)).unwrap();
// we default to a decent sized upper bound instead
let expected_limit = PEERS_PAGE_MAX_LIMIT;
assert_eq!(expected_limit, page1.peers.len() as u32);
remove_peers(deps.as_mut(), 1000);
}
#[test]
fn peers_pagination_works() {
let mut deps = init_contract();
let per_page = 2;
fill_peers(deps.as_mut(), 1);
let page1 = query_peers_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
// page should have 1 result on it
assert_eq!(1, page1.peers.len());
remove_peers(deps.as_mut(), 1);
fill_peers(deps.as_mut(), 2);
// page1 should have 2 results on it
let page1 = query_peers_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.peers.len());
remove_peers(deps.as_mut(), 2);
fill_peers(deps.as_mut(), 3);
// page1 still has 2 results
let page1 = query_peers_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.peers.len());
// retrieving the next page should start after the last key on this page
let start_after = page1.start_next_after.unwrap();
let page2 = query_peers_paged(
deps.as_ref(),
Option::from(start_after.to_string()),
Option::from(per_page),
)
.unwrap();
assert_eq!(1, page2.peers.len());
remove_peers(deps.as_mut(), 3);
fill_peers(deps.as_mut(), 4);
let page1 = query_peers_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
let start_after = page1.start_next_after.unwrap();
let page2 = query_peers_paged(
deps.as_ref(),
Option::from(start_after.to_string()),
Option::from(per_page),
)
.unwrap();
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.peers.len());
remove_peers(deps.as_mut(), 4);
}
}
+11
View File
@@ -0,0 +1,11 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::Addr;
use cw_storage_plus::Map;
use nym_ephemera_common::types::JsonPeerInfo;
pub(crate) const PEERS_PAGE_MAX_LIMIT: u32 = 75;
pub(crate) const PEERS_PAGE_DEFAULT_LIMIT: u32 = 50;
pub(crate) const PEERS: Map<'_, Addr, JsonPeerInfo> = Map::new("prs");
@@ -0,0 +1,63 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::ContractError;
use crate::peers::storage::PEERS;
use crate::state::STATE;
use cosmwasm_std::{DepsMut, MessageInfo, Response};
use nym_ephemera_common::types::JsonPeerInfo;
pub fn try_register_peer(
deps: DepsMut<'_>,
info: MessageInfo,
peer_info: JsonPeerInfo,
) -> Result<Response, ContractError> {
if PEERS.may_load(deps.storage, info.sender.clone())?.is_none() {
if STATE
.load(deps.storage)?
.group_addr
.is_voting_member(&deps.querier, &info.sender, None)?
.is_some()
{
PEERS.save(deps.storage, info.sender, &peer_info)?;
Ok(Default::default())
} else {
Err(ContractError::Unauthorized {})
}
} else {
Err(ContractError::AlreadyRegistered)
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::support::tests::fixtures::peer_fixture;
use crate::support::tests::helpers;
use crate::support::tests::helpers::GROUP_MEMBERS;
use cosmwasm_std::testing::mock_info;
use cw4::Member;
#[test]
fn peer_registration() {
let mut deps = helpers::init_contract();
let peer_info = peer_fixture("owner");
let info = mock_info("owner", &[]);
let ret = try_register_peer(deps.as_mut(), info.clone(), peer_info.clone()).unwrap_err();
assert_eq!(ret, ContractError::Unauthorized);
GROUP_MEMBERS.lock().unwrap().push((
Member {
addr: "owner".to_string(),
weight: 10,
},
1,
));
try_register_peer(deps.as_mut(), info.clone(), peer_info.clone()).unwrap();
let ret = try_register_peer(deps.as_mut(), info, peer_info).unwrap_err();
assert_eq!(ret, ContractError::AlreadyRegistered);
}
}

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