Compare commits

..

23 Commits

Author SHA1 Message Date
benedettadavico 6c491545f4 Support mnemonic in the NS agent 2025-07-04 19:39:02 +03:00
Andrej Mihajlov 8d2cd48da5 test: remove file after closing for a test 2025-06-12 15:39:52 +02:00
Andrej Mihajlov f2eb97514a Fix missing await on self.close_pool_inner() 2025-06-12 15:12:29 +02:00
Andrej Mihajlov 735535d902 Hide tokio behind feature 2025-06-06 15:21:43 +02:00
Andrej Mihajlov f7603a9973 Hide tokio and sqlx behind not(wasm32) 2025-06-06 15:21:43 +02:00
Andrej Mihajlov 693b8d5519 Exclude sqlx-pool-guard from wasm builds 2025-06-06 15:21:43 +02:00
Andrej Mihajlov f96103ab97 Log all tracing output just in case 2025-06-04 11:41:09 +02:00
Andrej Mihajlov b599ededf3 Include proc_pidinfo on iOS 2025-06-04 10:58:08 +02:00
Andrej Mihajlov d2114d3c2e Switch to tracing 2025-06-03 17:27:22 +02:00
Andrej Mihajlov 0356f0c682 Use log here 2025-06-03 15:12:55 +02:00
Andrej Mihajlov 365b12c069 Expose database path 2025-06-03 14:49:35 +02:00
Andrej Mihajlov 032281dc00 Clean up 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 9cc57f8f63 Improve windows 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 64c940a12a Cleanup 2025-06-03 10:09:11 +02:00
Andrej Mihajlov d6f0d50760 Revert 2025-06-03 10:09:11 +02:00
Andrej Mihajlov f6f361299c Use sqlite pool guard 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 3c5677b4ff Remove logs 2025-06-03 10:09:11 +02:00
Andrej Mihajlov b243062695 Document 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 946b10cc30 Add Windows impl 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 1c8831ec17 Add Windows implementation 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 3e606be545 Update Linux impl 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 3f8c2c096b Open file watch 2025-06-03 10:09:11 +02:00
Andrej Mihajlov 3ede03e1d1 Close sqlite pool before erroring 2025-06-03 10:09:11 +02:00
1306 changed files with 116520 additions and 45271 deletions
+11 -1
View File
@@ -14,6 +14,7 @@
# contracts
/contracts/mixnet @durch @jstuczyn
/contracts/vesting @durch @jstuczyn
/contracts/service-provider-directory @octol
# crypto code
/common/crypto/ @jstuczyn
@@ -21,5 +22,14 @@
/common/dkg/ @jstuczyn
/common/nymsphinx/ @jstuczyn
# rust sdk
/sdk/rust/ @octol
# nym-connect (rust)
/nym-connect/desktop/src-tauri/ @octol
# nym-wallet (rust)
/nym-wallet/src-tauri/ @octol
# documentation
/documentation @mfahampshire
/documentation @mfahampshire
+3 -3
View File
@@ -415,9 +415,9 @@
}
},
"node_modules/undici": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
"version": "5.28.5",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
"integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
+2 -2
View File
@@ -5,6 +5,7 @@ on:
paths:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'nym-api/**'
@@ -12,7 +13,6 @@ on:
- 'nym-network-monitor/**'
- 'nym-node/**'
- 'nym-node-status-api/**'
- 'nym-statistics-api/**'
- 'nym-outfox/**'
- 'nym-validator-rewarder/**'
- 'nyx-chain-watcher/**'
@@ -38,7 +38,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ arc-ubuntu-22.04, custom-windows-11, custom-macos-15 ]
os: [ arc-ubuntu-22.04, custom-windows-11, custom-runner-mac-m1 ]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
@@ -44,10 +44,8 @@ jobs:
echo "Tag is empty"
exit 1
fi
# first, list all tags for logging purposes
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
# check if there's a matching tag
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq -r --arg tag "$TAG" 'any(.tags[]; . == $tag)' )
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq --arg tag $TAG '.tags | contains([$tag])' )
if [[ $exists = "true" ]]; then
echo "Version '$TAG' defined in Cargo.toml ALREADY EXISTS as tag in harbor repo"
exit 1
@@ -55,5 +53,5 @@ jobs:
echo "Version '$TAG' doesn't exist on the remote"
else
echo "Unknown output '$exists'"
exit 2
exit 1
fi
@@ -1,59 +0,0 @@
name: ci-check-nym-stats-api-version
on:
pull_request:
paths:
- "nym-statistics-api/**"
env:
WORKING_DIRECTORY: "nym-statistics-api"
jobs:
check-if-tag-exists:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.4
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if git tag exists
run: |
TAG=${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
if [[ -z "$TAG" ]]; then
echo "Tag is empty"
exit 1
fi
git ls-remote --tags origin | awk '{print $2}'
if git ls-remote --tags origin | awk '{print $2}' | grep -q "refs/tags/$TAG$" ; then
echo "Tag '$TAG' ALREADY EXISTS on the remote"
exit 1
else
echo "Tag '$TAG' does not exist on the remote"
fi
- name: Check if harbor tag exists
run: |
TAG=${{ steps.get_version.outputs.result }}
registry=https://harbor.nymte.ch
repo_name=nym/nym-statistics-api
if [[ -z $TAG ]]; then
echo "Tag is empty"
exit 1
fi
# first, list all tags for logging purposes
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
# check if there's a matching tag
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq -r --arg tag "$TAG" 'any(.tags[]; . == $tag)' )
if [[ $exists = "true" ]]; then
echo "Version '$TAG' defined in Cargo.toml ALREADY EXISTS as tag in harbor repo"
exit 1
elif [[ $exists = "false" ]]; then
echo "Version '$TAG' doesn't exist on the remote"
else
echo "Unknown output '$exists'"
exit 2
fi
@@ -56,8 +56,6 @@ jobs:
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_ecash.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_pool_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_performance_contract.wasm $OUTPUT_DIR
- name: Deploy branch to CI www
continue-on-error: true
-1
View File
@@ -20,7 +20,6 @@ jobs:
runs-on: ubuntu-22.04
env:
CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps:
- uses: actions/checkout@v4
+5 -7
View File
@@ -19,11 +19,7 @@ jobs:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
include:
- os: arc-ubuntu-22.04
target: x86_64-unknown-linux-gnu
runs-on: ${{ matrix.os }}
runs-on: arc-ubuntu-22.04
outputs:
release_id: ${{ steps.create-release.outputs.id }}
@@ -70,6 +66,7 @@ jobs:
with:
name: my-artifact
path: |
target/release/explorer-api
target/release/nym-client
target/release/nym-socks5-client
target/release/nym-api
@@ -78,13 +75,14 @@ jobs:
target/release/nymvisor
target/release/nym-node
retention-days: 30
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
uses: softprops/action-gh-release@v2
if: github.event_name == 'release'
with:
files: |
target/release/explorer-api
target/release/nym-client
target/release/nym-socks5-client
target/release/nym-api
-51
View File
@@ -1,51 +0,0 @@
name: Build and upload Nym APU container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "."
CONTAINER_NAME: "nym-api"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.4
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-api/Cargo.toml
- name: Remove existing tag if exists
run: |
echo "Checking if tag ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }} exists..."
if git rev-parse ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
echo "Tag ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }} already exists"
git push --delete origin ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.CONTAINER_NAME }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f nym-api.dockerfile ${{ env.WORKING_DIRECTORY }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
@@ -1,42 +0,0 @@
name: Build and upload Nym Statistics API container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-statistics-api"
CONTAINER_NAME: "nym-statistics-api"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.4
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
+1
View File
@@ -40,6 +40,7 @@ validator-config
validator-api-config.toml
dist
storybook-static
envs/qwerty.env
.parcel-cache
**/.DS_Store
cpu-cycles/libcpucycles/build
-24
View File
@@ -4,30 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2025.11-cheddar] (2025-06-10)
- No autoremoval of peers ([#5831])
- Set cached storage counters to 0 ([#5812])
- hack: temporarily use next.config.js instead of next.config.ts ([#5805])
- chore: resolve 1.87 clippy warnings ([#5802])
- Nym Statistics API ([#5800])
- QoL: RequestPath trait for http-api-client ([#5788])
- Fix contains ticketbook function that always returned true ([#5787])
- swap a decode into a fromrow to please future postgres feature ([#5785])
- Make address cache configurable ([#5784])
- Track wireguard credential retries ([#5783])
[#5831]: https://github.com/nymtech/nym/pull/5831
[#5812]: https://github.com/nymtech/nym/pull/5812
[#5805]: https://github.com/nymtech/nym/pull/5805
[#5802]: https://github.com/nymtech/nym/pull/5802
[#5800]: https://github.com/nymtech/nym/pull/5800
[#5788]: https://github.com/nymtech/nym/pull/5788
[#5787]: https://github.com/nymtech/nym/pull/5787
[#5785]: https://github.com/nymtech/nym/pull/5785
[#5784]: https://github.com/nymtech/nym/pull/5784
[#5783]: https://github.com/nymtech/nym/pull/5783
## [2025.10-brie] (2025-05-27)
- Backport PR 5779 ([#5801])
Generated
+581 -1422
View File
File diff suppressed because it is too large Load Diff
+12 -17
View File
@@ -33,14 +33,11 @@ members = [
"common/commands",
"common/config",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/contracts-common-testing",
"common/cosmwasm-smart-contracts/easy_addr",
"common/cosmwasm-smart-contracts/contracts-common", "common/cosmwasm-smart-contracts/easy_addr",
"common/cosmwasm-smart-contracts/ecash-contract",
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract", "common/cosmwasm-smart-contracts/nym-performance-contract",
"common/cosmwasm-smart-contracts/nym-pool-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/credential-storage",
"common/credential-utils",
@@ -67,8 +64,6 @@ members = [
"common/nym-id",
"common/nym-metrics",
"common/nym_offline_compact_ecash",
"common/nymnoise",
"common/nymnoise/keys",
"common/nymsphinx",
"common/nymsphinx/acknowledgements",
"common/nymsphinx/addressing",
@@ -102,6 +97,7 @@ members = [
"common/wireguard-types",
"documentation/autodoc",
"gateway",
"integrations/bity",
"nym-api",
"nym-api/nym-api-requests",
"nym-browser-extension/storage",
@@ -116,7 +112,6 @@ members = [
"nym-node/nym-node-metrics",
"nym-node/nym-node-requests",
"nym-outfox",
"nym-statistics-api",
"nym-validator-rewarder",
"nyx-chain-watcher",
"sdk/ffi/cpp",
@@ -137,7 +132,7 @@ members = [
"tools/internal/testnet-manager",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"tools/internal/validator-status-check",
"tools/internal/testnet-manager/dkg-bypass-contract", "tools/internal/validator-status-check",
"tools/nym-cli",
"tools/nym-id-cli",
"tools/nym-nr-query",
@@ -158,7 +153,6 @@ default-members = [
"nym-node",
"nym-node-status-api/nym-node-status-agent",
"nym-node-status-api/nym-node-status-api",
"nym-statistics-api",
"nym-validator-rewarder",
"nyx-chain-watcher",
"service-providers/authenticator",
@@ -205,7 +199,7 @@ bloomfilter = "3.0.1"
bs58 = "0.5.1"
bytecodec = "0.4.15"
bytes = "1.10.1"
cargo_metadata = "0.19.2"
cargo_metadata = "0.18.1"
celes = "2.6.0"
cfg-if = "1.0.0"
chacha20 = "0.9.0"
@@ -313,9 +307,8 @@ serde_with = "3.9.0"
serde_yaml = "0.9.25"
sha2 = "0.10.9"
si-scale = "0.2.3"
snow = "0.9.6"
sphinx-packet = "=0.6.0"
sqlx = "0.8.6"
sqlx = "0.7.4"
strum = "0.26"
strum_macros = "0.26"
subtle-encoding = "0.5"
@@ -323,10 +316,10 @@ syn = "1"
sysinfo = "0.33.0"
tap = "1.0.1"
tar = "0.4.44"
tempfile = "3.20"
tempfile = "3.19"
thiserror = "2.0"
time = "0.3.41"
tokio = "1.45"
tokio = "1.44"
tokio-postgres = "0.7"
tokio-stream = "0.1.17"
tokio-test = "0.4.4"
@@ -353,6 +346,7 @@ utoipauto = "0.2"
uuid = "*"
vergen = { version = "=8.3.1", default-features = false }
walkdir = "2"
wasm-bindgen-test = "0.3.49"
x25519-dalek = "2.0.0"
zeroize = "1.7.0"
@@ -370,6 +364,9 @@ subtle = "2.5.0"
# cosmwasm-related
cosmwasm-schema = "=2.2.2"
cosmwasm-std = "=2.2.2"
# use 1.0.1 as that's the version used by cosmwasm-std 2.2.1
# (and ideally we don't want to pull the same dependency twice)
serde-json-wasm = "=1.0.1"
# same version as used by cosmwasm
cw-utils = "=2.0.0"
cw-storage-plus = "=2.0.0"
@@ -377,7 +374,6 @@ cw2 = { version = "=2.0.0" }
cw3 = { version = "=2.0.0" }
cw4 = { version = "=2.0.0" }
cw-controllers = { version = "=2.0.0" }
cw-multi-test = "=2.3.2"
# cosmrs-related
bip32 = { version = "0.5.3", default-features = false }
@@ -398,7 +394,6 @@ serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.99"
wasm-bindgen-futures = "0.4.49"
wasm-bindgen-test = "0.3.49"
wasmtimer = "0.4.1"
web-sys = "0.3.76"
+1 -1
View File
@@ -133,7 +133,7 @@ clippy: sdk-wasm-lint
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract nym_ecash cw3_flex_multisig cw4_group nym_coconut_dkg nym_pool_contract nym_performance_contract
CONTRACTS=vesting_contract mixnet_contract nym_ecash cw3_flex_multisig cw4_group nym_coconut_dkg
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.57"
version = "1.1.56"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -2048,11 +2048,10 @@
}
},
"node_modules/http-proxy-middleware": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
"integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz",
"integrity": "sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/http-proxy": "^1.17.8",
"http-proxy": "^1.18.1",
@@ -6096,9 +6095,9 @@
}
},
"http-proxy-middleware": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
"integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz",
"integrity": "sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg==",
"dev": true,
"requires": {
"@types/http-proxy": "^1.17.8",
+1 -1
View File
@@ -318,7 +318,7 @@ impl Handler {
async fn handle_text_message(&mut self, msg: String) -> Option<WsMessage> {
debug!("Handling text message request");
trace!("Content: {msg:?}");
trace!("Content: {:?}", msg);
self.received_response_type = ReceivedResponseType::Text;
let client_request = ClientRequest::try_from_text(msg);
+2 -2
View File
@@ -68,9 +68,9 @@ impl Listener {
new_conn = tcp_listener.accept() => {
match new_conn {
Ok((mut socket, remote_addr)) => {
debug!("Received connection from {remote_addr:?}");
debug!("Received connection from {:?}", remote_addr);
if self.state.is_connected() {
warn!("Tried to open a duplicate websocket connection. The request came from {remote_addr}");
warn!("Tried to open a duplicate websocket connection. The request came from {}", remote_addr);
// if we've already got a connection, don't allow another one
// while we only ever want to accept a single connection, we don't want
// to leave clients hanging (and also allow for reconnection if it somehow
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.57"
version = "1.1.56"
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"
+1 -1
View File
@@ -137,7 +137,7 @@ impl AsyncFileWatcher {
log::error!("the file watcher receiver has been dropped!");
}
} else {
log::debug!("will not propagate information about {event:?}");
log::debug!("will not propagate information about {:?}", event);
}
}
Err(err) => {
@@ -108,7 +108,7 @@ impl GatewayClient {
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// use gateways key as a ref to an x25519_dalek key
let dh = gateway_key.inner().diffie_hellman(&self.pub_key);
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
@@ -117,7 +117,7 @@ impl GatewayClient {
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// use gateways key as a ref to an x25519_dalek key
let dh = gateway_key.inner().diffie_hellman(&self.pub_key);
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
@@ -117,7 +117,7 @@ impl GatewayClient {
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// use gateways key as a ref to an x25519_dalek key
let dh = gateway_key.inner().diffie_hellman(&self.pub_key);
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
@@ -169,7 +169,7 @@ impl GatewayClient {
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// use gateways key as a ref to an x25519_dalek key
let dh = gateway_key.inner().diffie_hellman(&self.pub_key);
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
@@ -169,7 +169,7 @@ impl GatewayClient {
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// use gateways key as a ref to an x25519_dalek key
let dh = gateway_key.inner().diffie_hellman(&self.pub_key);
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
+1 -1
View File
@@ -11,7 +11,7 @@ impl std::fmt::Display for BandwidthStatusMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BandwidthStatusMessage::RemainingBandwidth(b) => {
write!(f, "remaining bandwidth: {b}")
write!(f, "remaining bandwidth: {}", b)
}
BandwidthStatusMessage::NoBandwidth => write!(f, "no bandwidth left"),
}
+1 -3
View File
@@ -44,6 +44,7 @@ nym-sphinx = { path = "../nymsphinx" }
nym-statistics-common = { path = "../statistics" }
nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology", features = ["persistence"] }
nym-mixnet-client = { path = "../client-libs/mixnet-client", default-features = false }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-task = { path = "../task" }
nym-credentials-interface = { path = "../credentials-interface" }
@@ -56,9 +57,6 @@ nym-client-core-surb-storage = { path = "./surb-storage" }
nym-client-core-gateways-storage = { path = "./gateways-storage" }
nym-ecash-time = { path = "../ecash-time" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
nym-mixnet-client = { path = "../client-libs/mixnet-client", default-features = false }
### For serving prometheus metrics
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper]
workspace = true
@@ -418,9 +418,6 @@ pub struct Traffic {
/// will be routed as usual, to the entry gateway, through three mix nodes, egressing
/// through the exit gateway. If mix hops are disabled, traffic will be routed directly
/// from the entry gateway to the exit gateway, bypassing the mix nodes.
///
/// This overrides the `use_legacy_sphinx_format` setting as reduced mix hops
/// requires use of the updated SURB packet format.
pub disable_mix_hops: bool,
}
@@ -87,7 +87,7 @@ impl StorageManager {
sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id)
.fetch_one(&self.connection_pool)
.await
.map(|result| result.exists == 1)
.map(|result| result.exists == Some(1))
}
pub(crate) async fn maybe_get_registered_gateway(
@@ -456,7 +456,7 @@ where
log::error!("Could not authenticate and start up the gateway connection - {err}");
ClientCoreError::GatewayClientError {
gateway_id: details.gateway_id.to_base58_string(),
source: Box::new(err),
source: err,
}
};
@@ -146,7 +146,7 @@ impl MixTrafficController {
Some(client_request) => {
match self.gateway_transceiver.send_client_request(client_request).await {
Ok(_) => (),
Err(e) => error!("Failed to send client request: {e}"),
Err(e) => error!("Failed to send client request: {}", e),
};
},
None => {
@@ -65,7 +65,7 @@ impl AcknowledgementListener {
return;
}
trace!("Received {frag_id} from the mix network");
trace!("Received {} from the mix network", frag_id);
self.stats_tx
.report(PacketStatisticsEvent::RealAckReceived(ack_content.len()).into());
if let Err(err) = self
@@ -126,7 +126,7 @@ impl ActionController {
fn handle_insert(&mut self, pending_acks: Vec<PendingAcknowledgement>) {
for pending_ack in pending_acks {
let frag_id = pending_ack.message_chunk.fragment_identifier();
trace!("{frag_id} is inserted");
trace!("{} is inserted", frag_id);
if self
.pending_acks_data
@@ -161,16 +161,22 @@ impl ActionController {
let new_queue_key = self.pending_acks_timers.insert(frag_id, timeout);
*queue_key = Some(new_queue_key)
} else {
debug!("Tried to START TIMER on pending ack that is already gone! - {frag_id}");
debug!(
"Tried to START TIMER on pending ack that is already gone! - {}",
frag_id
);
}
}
fn handle_remove(&mut self, frag_id: FragmentIdentifier) {
trace!("{frag_id} is getting removed");
trace!("{} is getting removed", frag_id);
match self.pending_acks_data.remove(&frag_id) {
None => {
debug!("Tried to REMOVE pending ack that is already gone! - {frag_id}");
debug!(
"Tried to REMOVE pending ack that is already gone! - {}",
frag_id
);
}
Some((_, queue_key)) => {
if let Some(queue_key) = queue_key {
@@ -182,7 +188,10 @@ impl ActionController {
} else {
// I'm not 100% sure if having a `None` key is even possible here
// (REMOVE would have to be called before START TIMER),
debug!("Tried to REMOVE pending ack without TIMER active - {frag_id}");
debug!(
"Tried to REMOVE pending ack without TIMER active - {}",
frag_id
);
}
}
}
@@ -191,7 +200,7 @@ impl ActionController {
// initiated basically as a first step of retransmission. At first data has its delay updated
// (as new sphinx packet was created with new expected delivery time)
fn handle_update_pending_ack(&mut self, frag_id: FragmentIdentifier, delay: SphinxDelay) {
trace!("{frag_id} is updating its delay");
trace!("{} is updating its delay", frag_id);
// TODO: is it possible to solve this without either locking or temporarily removing the value?
if let Some((pending_ack_data, queue_key)) = self.pending_acks_data.remove(&frag_id) {
// this Action is triggered by `RetransmissionRequestListener` (for 'normal' packets)
@@ -204,7 +213,10 @@ impl ActionController {
self.pending_acks_data
.insert(frag_id, (Arc::new(inner_data), queue_key));
} else {
debug!("Tried to UPDATE TIMER on pending ack that is already gone! - {frag_id}");
debug!(
"Tried to UPDATE TIMER on pending ack that is already gone! - {}",
frag_id
);
}
}
@@ -12,7 +12,7 @@ use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit};
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessage, ReplyMessage};
use nym_sphinx::anonymous_replies::ReplySurbWithKeyRotation;
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
use nym_sphinx::message::NymMessage;
use nym_sphinx::params::{PacketSize, PacketType};
@@ -44,10 +44,7 @@ pub enum PreparationError {
}
impl PreparationError {
fn return_surbs(
self,
returned_surbs: Vec<ReplySurbWithKeyRotation>,
) -> SurbWrappedPreparationError {
fn return_surbs(self, returned_surbs: Vec<ReplySurb>) -> SurbWrappedPreparationError {
SurbWrappedPreparationError {
source: self,
returned_surbs: Some(returned_surbs),
@@ -61,7 +58,7 @@ pub struct SurbWrappedPreparationError {
#[source]
source: PreparationError,
returned_surbs: Option<Vec<ReplySurbWithKeyRotation>>,
returned_surbs: Option<Vec<ReplySurb>>,
}
impl<T> From<T> for SurbWrappedPreparationError
@@ -105,9 +102,6 @@ pub(crate) struct Config {
/// will be routed as usual, to the entry gateway, through three mix nodes, egressing
/// through the exit gateway. If mix hops are disabled, traffic will be routed directly
/// from the entry gateway to the exit gateway, bypassing the mix nodes.
///
/// This overrides the `use_legacy_sphinx_format` setting as reduced mix hops
/// requires use of the updated SURB packet format.
disable_mix_hops: bool,
/// Average delay a data packet is going to get delay at a single mixnode.
@@ -162,12 +156,8 @@ impl Config {
}
/// Configure whether messages senders using this config should use mix hops or not when sending messages.
///
/// This overrides the `use_legacy_sphinx_format` setting as disabled mix hops
/// requires use of the updated SURB packet format.
pub fn disable_mix_hops(mut self, disable_mix_hops: bool) -> Self {
self.disable_mix_hops = disable_mix_hops;
self.use_legacy_sphinx_format = false;
self
}
}
@@ -278,10 +268,10 @@ where
}
}
async fn generate_reply_surbs(
async fn generate_reply_surbs_with_keys(
&mut self,
amount: usize,
) -> Result<Vec<ReplySurbWithKeyRotation>, PreparationError> {
) -> Result<(Vec<ReplySurb>, Vec<SurbEncryptionKey>), PreparationError> {
let topology_permit = self.topology_access.get_read_permit().await;
let topology = self.get_topology(&topology_permit)?;
@@ -291,14 +281,19 @@ where
topology,
)?;
Ok(reply_surbs)
let reply_keys = reply_surbs
.iter()
.map(|s| *s.encryption_key())
.collect::<Vec<_>>();
Ok((reply_surbs, reply_keys))
}
pub(crate) async fn try_send_single_surb_message(
&mut self,
target: AnonymousSenderTag,
message: ReplyMessage,
reply_surb: ReplySurbWithKeyRotation,
reply_surb: ReplySurb,
is_extra_surb_request: bool,
) -> Result<(), SurbWrappedPreparationError> {
let msg = NymMessage::new_reply(message);
@@ -352,7 +347,7 @@ where
pub(crate) async fn try_request_additional_reply_surbs(
&mut self,
from: AnonymousSenderTag,
reply_surb: ReplySurbWithKeyRotation,
reply_surb: ReplySurb,
amount: u32,
) -> Result<(), SurbWrappedPreparationError> {
debug!("requesting {amount} reply SURBs from {from}");
@@ -392,7 +387,7 @@ where
&mut self,
target: AnonymousSenderTag,
fragments: Vec<FragmentWithMaxRetransmissions>,
reply_surbs: Vec<ReplySurbWithKeyRotation>,
reply_surbs: Vec<ReplySurb>,
lane: TransmissionLane,
) -> Result<(), SurbWrappedPreparationError> {
// TODO: technically this is performing an unnecessary cloning, but in the grand scheme of things
@@ -409,7 +404,7 @@ where
&mut self,
target: AnonymousSenderTag,
fragments: Vec<(TransmissionLane, FragmentWithMaxRetransmissions)>,
reply_surbs: Vec<ReplySurbWithKeyRotation>,
reply_surbs: Vec<ReplySurb>,
) -> Result<(), SurbWrappedPreparationError> {
let prepared_fragments = self
.prepare_reply_chunks_for_sending(
@@ -546,12 +541,8 @@ where
) -> Result<(), PreparationError> {
debug!("Sending additional reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient);
let reply_surbs = self.generate_reply_surbs(amount as usize).await?;
let reply_keys = reply_surbs
.iter()
.map(|s| *s.encryption_key())
.collect::<Vec<_>>();
let (reply_surbs, reply_keys) =
self.generate_reply_surbs_with_keys(amount as usize).await?;
let message = NymMessage::new_repliable(RepliableMessage::new_additional_surbs(
self.config.use_legacy_sphinx_format,
@@ -588,12 +579,9 @@ where
) -> Result<(), SurbWrappedPreparationError> {
debug!("Sending message with reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient);
let reply_surbs = self.generate_reply_surbs(num_reply_surbs as usize).await?;
let reply_keys = reply_surbs
.iter()
.map(|s| *s.encryption_key())
.collect::<Vec<_>>();
let (reply_surbs, reply_keys) = self
.generate_reply_surbs_with_keys(num_reply_surbs as usize)
.await?;
let message = NymMessage::new_repliable(RepliableMessage::new_data(
self.config.use_legacy_sphinx_format,
@@ -641,7 +629,7 @@ where
pub(crate) async fn prepare_reply_chunks_for_sending(
&mut self,
fragments: Vec<Fragment>,
reply_surbs: Vec<ReplySurbWithKeyRotation>,
reply_surbs: Vec<ReplySurb>,
) -> Result<Vec<PreparedFragment>, SurbWrappedPreparationError> {
debug_assert_eq!(
fragments.len(),
@@ -677,7 +665,7 @@ where
pub(crate) async fn try_prepare_single_reply_chunk_for_sending(
&mut self,
reply_surb: ReplySurbWithKeyRotation,
reply_surb: ReplySurb,
chunk: Fragment,
) -> Result<PreparedFragment, SurbWrappedPreparationError> {
let topology_permit = self.topology_access.get_read_permit().await;
@@ -202,7 +202,7 @@ where
// well technically the message was not sent just yet, but now it's up to internal
// queues and client load rather than the required delay. So realistically we can treat
// whatever is about to happen as negligible additional delay.
trace!("{frag_id} is about to get sent to the mixnet");
trace!("{} is about to get sent to the mixnet", frag_id);
if let Err(err) = self.sent_notifier.unbounded_send(frag_id) {
error!("Failed to notify about sent message: {err}");
}
@@ -164,11 +164,11 @@ impl SendingDelayController {
self.current_multiplier()
);
if self.current_multiplier() > 0 {
log::debug!("{status_str}");
log::debug!("{}", status_str);
} else if self.current_multiplier() > 1 {
log::info!("{status_str}");
log::info!("{}", status_str);
} else if self.current_multiplier() > 2 {
log::warn!("{status_str}");
log::warn!("{}", status_str);
}
self.time_when_logged_about_elevated_multiplier = now;
}
@@ -221,7 +221,10 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
let stored_messages = std::mem::take(&mut guard.messages);
if !stored_messages.is_empty() {
if let Err(err) = sender.unbounded_send(stored_messages) {
error!("The sender channel we just received is already invalidated - {err:?}");
error!(
"The sender channel we just received is already invalidated - {:?}",
err
);
// put the values back to the buffer
// the returned error has two fields: err: SendError and val: T,
// where val is the value that was failed to get sent;
@@ -11,7 +11,7 @@ use futures::StreamExt;
use log::{debug, error, info, trace, warn};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::anonymous_replies::ReplySurbWithKeyRotation;
use nym_sphinx::anonymous_replies::ReplySurb;
use nym_sphinx::chunking::fragment::FragmentIdentifier;
use nym_task::connections::{ConnectionId, TransmissionLane};
use nym_task::TaskClient;
@@ -217,14 +217,14 @@ where
.surbs_storage_ref()
.contains_surbs_for(&recipient_tag)
{
warn!("received reply request for {recipient_tag:?} but we don't have any surbs stored for that recipient!");
warn!("received reply request for {:?} but we don't have any surbs stored for that recipient!", recipient_tag);
return;
}
trace!("handling reply to {recipient_tag:?}");
trace!("handling reply to {:?}", recipient_tag);
let mut fragments = self.message_handler.split_reply_message(data);
let total_size = fragments.len();
trace!("This reply requires {total_size:?} SURBs");
trace!("This reply requires {:?} SURBs", total_size);
let available_surbs = self
.full_reply_storage
@@ -327,7 +327,10 @@ where
.await
{
let err = err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
warn!("failed to request additional surbs from {target:?} - {err}");
warn!(
"failed to request additional surbs from {:?} - {err}",
target
);
return Err(err);
} else {
self.full_reply_storage
@@ -406,7 +409,10 @@ where
err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
self.re_insert_pending_retransmission(&target, to_take);
warn!("failed to clear pending retransmission queue for {target:?} - {err}");
warn!(
"failed to clear pending retransmission queue for {:?} - {err}",
target
);
return;
}
};
@@ -483,7 +489,7 @@ where
let err =
err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
self.re_insert_pending_replies(&target, to_send);
warn!("failed to clear pending queue for {target:?} - {err}");
warn!("failed to clear pending queue for {:?} - {err}", target);
}
} else {
trace!("the pending queue is empty");
@@ -493,7 +499,7 @@ where
async fn handle_received_surbs(
&mut self,
from: AnonymousSenderTag,
reply_surbs: Vec<ReplySurbWithKeyRotation>,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
) {
trace!("handling received surbs");
@@ -810,7 +816,7 @@ where
if diff > max_drop_wait {
to_remove.push(*pending_reply_target)
} else {
debug!("We haven't received any surbs in {diff:?} from {pending_reply_target}. Going to explicitly ask for more");
debug!("We haven't received any surbs in {:?} from {pending_reply_target}. Going to explicitly ask for more", diff);
to_request.push(*pending_reply_target);
}
}
@@ -6,7 +6,7 @@ use futures::channel::{mpsc, oneshot};
use log::error;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::anonymous_replies::ReplySurbWithKeyRotation;
use nym_sphinx::anonymous_replies::ReplySurb;
use nym_task::connections::{ConnectionId, TransmissionLane};
use std::sync::Weak;
@@ -81,7 +81,7 @@ impl ReplyControllerSender {
pub(crate) fn send_additional_surbs(
&self,
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurbWithKeyRotation>,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
) -> Result<(), ReplyControllerSenderError> {
self.0
@@ -167,7 +167,7 @@ pub enum ReplyControllerMessage {
AdditionalSurbs {
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurbWithKeyRotation>,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
},
@@ -93,7 +93,7 @@ impl StatisticsControl {
None,
);
if let Err(err) = self.report_tx.send(report_message).await {
log::error!("Failed to report client stats: {err:?}");
log::error!("Failed to report client stats: {:?}", err);
} else {
self.stats.reset();
}
@@ -4,7 +4,7 @@
use async_trait::async_trait;
use log::{debug, error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{NymTopology, NymTopologyMetadata};
use nym_topology::NymTopology;
use nym_validator_client::UserAgent;
use rand::prelude::SliceRandom;
use rand::thread_rng;
@@ -89,84 +89,55 @@ impl NymApiTopologyProvider {
let rewarded_set_fut = self.validator_client.get_current_rewarded_set();
let topology = if self.config.use_extended_topology {
let all_nodes_fut = self.validator_client.get_all_basic_nodes_with_metadata();
let all_nodes_fut = self.validator_client.get_all_basic_nodes();
// Join rewarded_set_fut and all_nodes_fut concurrently
let (rewarded_set, all_nodes_res) = futures::try_join!(rewarded_set_fut, all_nodes_fut)
let (rewarded_set, all_nodes) = futures::try_join!(rewarded_set_fut, all_nodes_fut)
.inspect_err(|err| error!("failed to get network nodes: {err}"))
.ok()?;
let metadata = all_nodes_res.metadata;
let all_nodes = all_nodes_res.nodes;
debug!(
"there are {} nodes on the network (before filtering)",
all_nodes.len()
);
let nodes_filtered = all_nodes
.into_iter()
.filter(|n| n.performance.round_to_integer() >= self.config.min_node_performance())
.collect::<Vec<_>>();
let mut topology = NymTopology::new_empty(rewarded_set);
topology.add_additional_nodes(all_nodes.iter().filter(|n| {
n.performance.round_to_integer() >= self.config.min_node_performance()
}));
NymTopology::new(
NymTopologyMetadata::new(metadata.rotation_id, metadata.absolute_epoch_id),
rewarded_set,
Vec::new(),
)
.with_skimmed_nodes(&nodes_filtered)
topology
} else {
// if we're not using extended topology, we're only getting active set mixnodes and gateways
let mixnodes_fut = self
.validator_client
.get_all_basic_active_mixing_assigned_nodes_with_metadata();
.get_all_basic_active_mixing_assigned_nodes();
// TODO: we really should be getting ACTIVE gateways only
let gateways_fut = self
.validator_client
.get_all_basic_entry_assigned_nodes_v2();
let gateways_fut = self.validator_client.get_all_basic_entry_assigned_nodes();
let (rewarded_set, mixnodes_res, gateways_res) =
let (rewarded_set, mixnodes, gateways) =
futures::try_join!(rewarded_set_fut, mixnodes_fut, gateways_fut)
.inspect_err(|err| {
error!("failed to get network nodes: {err}");
})
.ok()?;
let metadata = mixnodes_res.metadata;
let mixnodes = mixnodes_res.nodes;
if gateways_res.metadata != metadata {
warn!("inconsistent nodes metadata between mixnodes and gateways calls! {metadata:?} and {:?}", gateways_res.metadata);
return None;
}
let gateways = gateways_res.nodes;
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
let mut nodes = Vec::new();
for mix in mixnodes {
if mix.performance.round_to_integer() >= self.config.min_mixnode_performance {
nodes.push(mix)
}
}
for gateway in gateways {
if gateway.performance.round_to_integer() >= self.config.min_gateway_performance {
nodes.push(gateway)
}
}
let mut topology = NymTopology::new_empty(rewarded_set);
topology.add_additional_nodes(mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
}));
topology.add_additional_nodes(gateways.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_gateway_performance
}));
NymTopology::new(
NymTopologyMetadata::new(metadata.rotation_id, metadata.absolute_epoch_id),
rewarded_set,
Vec::new(),
)
.with_skimmed_nodes(&nodes)
topology
};
if !topology.is_minimally_routable() {
@@ -211,7 +211,7 @@ impl<T> TransmissionBuffer<T> {
};
let msg = self.pop_front_from_lane(&lane)?;
log::trace!("picking to send from lane: {lane:?}");
log::trace!("picking to send from lane: {:?}", lane);
Some((lane, msg))
}
+5 -10
View File
@@ -18,7 +18,7 @@ pub enum ClientCoreError {
#[error("gateway client error ({gateway_id}): {source}")]
GatewayClientError {
gateway_id: String,
source: Box<GatewayClientError>,
source: GatewayClientError,
},
#[error("custom gateway client error: {source}")]
@@ -88,7 +88,10 @@ pub enum ClientCoreError {
},
#[error("failed to establish connection to gateway: {source}")]
GatewayConnectionFailure { source: Box<tungstenite::Error> },
GatewayConnectionFailure {
#[from]
source: tungstenite::Error,
},
#[cfg(target_arch = "wasm32")]
#[error("failed to establish gateway connection (wasm)")]
@@ -224,14 +227,6 @@ pub enum ClientCoreError {
HkdfDerivationError {},
}
impl From<tungstenite::Error> for ClientCoreError {
fn from(err: tungstenite::Error) -> ClientCoreError {
ClientCoreError::GatewayConnectionFailure {
source: Box::new(err),
}
}
}
/// Set of messages that the client can send to listeners via the task manager
#[derive(Debug)]
pub enum ClientCoreStatusMessage {
+6 -6
View File
@@ -107,10 +107,10 @@ pub async fn gateways_for_init<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_all_basic_entry_assigned_nodes_v2().await?.nodes;
let gateways = client.get_all_basic_entry_assigned_nodes().await?;
info!("nym api reports {} gateways", gateways.len());
log::trace!("Gateways: {gateways:#?}");
log::trace!("Gateways: {:#?}", gateways);
// filter out gateways below minimum performance and ones that could operate as a mixnode
// (we don't want instability)
@@ -121,7 +121,7 @@ pub async fn gateways_for_init<R: Rng>(
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<_>>();
log::debug!("After checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {valid_gateways:#?}");
log::trace!("Valid gateways: {:#?}", valid_gateways);
log::info!(
"and {} after validity and performance filtering",
@@ -286,7 +286,7 @@ pub(super) fn get_specified_gateway(
gateways: &[RoutingNode],
must_use_tls: bool,
) -> Result<RoutingNode, ClientCoreError> {
log::debug!("Requesting specified gateway: {gateway_identity}");
log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = ed25519::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
@@ -329,7 +329,7 @@ pub(super) async fn register_with_gateway(
log::warn!("Failed to establish connection with gateway!");
ClientCoreError::GatewayClientError {
gateway_id: gateway_id.to_base58_string(),
source: Box::new(err),
source: err,
}
})?;
let auth_response = gateway_client
@@ -339,7 +339,7 @@ pub(super) async fn register_with_gateway(
log::warn!("Failed to register with the gateway {gateway_id}: {err}");
ClientCoreError::GatewayClientError {
gateway_id: gateway_id.to_base58_string(),
source: Box::new(err),
source: err,
}
})?;
+1 -1
View File
@@ -232,7 +232,7 @@ where
} => {
log::debug!("GatewaySetup::ReuseConnection");
Ok(reuse_gateway_connection(
*authenticated_ephemeral_client,
authenticated_ephemeral_client,
*gateway_details,
managed_keys,
))
+2 -2
View File
@@ -218,7 +218,7 @@ pub enum GatewaySetup {
ReuseConnection {
/// The authenticated ephemeral client that was created during `init`
authenticated_ephemeral_client: Box<InitGatewayClient>,
authenticated_ephemeral_client: InitGatewayClient,
// Details of this pre-initialised client (i.e. gateway and keys)
gateway_details: Box<GatewayRegistration>,
@@ -261,7 +261,7 @@ impl GatewaySetup {
pub fn try_reuse_connection(init_res: InitialisationResult) -> Result<Self, ClientCoreError> {
if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client {
Ok(GatewaySetup::ReuseConnection {
authenticated_ephemeral_client: Box::new(authenticated_ephemeral_client),
authenticated_ephemeral_client,
gateway_details: Box::new(init_res.gateway_registration),
client_keys: init_res.client_keys,
})
@@ -1,8 +0,0 @@
/*
* Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
-- default value of 0 implies 'unknown' variant
ALTER TABLE reply_surb
ADD COLUMN encoded_key_rotation TINYINT NOT NULL DEFAULT 0;
@@ -216,10 +216,7 @@ impl StorageManager {
) -> Result<Vec<StoredReplySurb>, sqlx::Error> {
sqlx::query_as!(
StoredReplySurb,
r#"
SELECT reply_surb_sender_id, reply_surb, encoded_key_rotation as "encoded_key_rotation: u8" FROM reply_surb
WHERE reply_surb_sender_id = ?
"#,
"SELECT * FROM reply_surb WHERE reply_surb_sender_id = ?",
sender_id
)
.fetch_all(&*self.connection_pool)
@@ -244,11 +241,10 @@ impl StorageManager {
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
INSERT INTO reply_surb(reply_surb_sender_id, reply_surb, encoded_key_rotation) VALUES (?, ?, ?);
INSERT INTO reply_surb(reply_surb_sender_id, reply_surb) VALUES (?, ?);
"#,
stored_reply_surb.reply_surb_sender_id,
stored_reply_surb.reply_surb,
stored_reply_surb.encoded_key_rotation
stored_reply_surb.reply_surb
)
.execute(&*self.connection_pool)
.await?;
@@ -8,10 +8,8 @@ use nym_crypto::Digest;
use nym_sphinx::addressing::clients::{Recipient, RecipientBytes};
use nym_sphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, SENDER_TAG_SIZE};
use nym_sphinx::anonymous_replies::{
ReplySurb, ReplySurbWithKeyRotation, SurbEncryptionKey, SurbEncryptionKeySize,
};
use nym_sphinx::params::{ReplySurbKeyDigestAlgorithm, SphinxKeyRotation};
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey, SurbEncryptionKeySize};
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
#[derive(Debug, Clone)]
pub struct StoredSenderTag {
@@ -148,40 +146,24 @@ impl TryFrom<StoredSurbSender> for (AnonymousSenderTag, i64) {
pub struct StoredReplySurb {
pub reply_surb_sender_id: i64,
pub reply_surb: Vec<u8>,
// encodes only whether it's 'even', 'odd' or 'unknown' (default)
// and not the whole id because that's redundant
pub encoded_key_rotation: u8,
}
impl StoredReplySurb {
pub fn new(reply_surb_sender_id: i64, reply_surb: &ReplySurbWithKeyRotation) -> Self {
pub fn new(reply_surb_sender_id: i64, reply_surb: &ReplySurb) -> Self {
StoredReplySurb {
reply_surb_sender_id,
reply_surb: reply_surb.inner_reply_surb().to_bytes(),
encoded_key_rotation: reply_surb.key_rotation() as u8,
reply_surb: reply_surb.to_bytes(),
}
}
}
impl TryFrom<StoredReplySurb> for ReplySurbWithKeyRotation {
impl TryFrom<StoredReplySurb> for ReplySurb {
type Error = StorageError;
fn try_from(value: StoredReplySurb) -> Result<Self, Self::Error> {
let key_rotation =
SphinxKeyRotation::try_from(value.encoded_key_rotation).map_err(|err| {
StorageError::CorruptedData {
details: format!("stored key rotation was malformed: {err}"),
}
})?;
let reply_surb = ReplySurb::from_bytes(&value.reply_surb).map_err(|err| {
StorageError::CorruptedData {
details: format!("failed to recover the reply surb: {err}"),
}
})?;
Ok(reply_surb.with_key_rotation(key_rotation))
ReplySurb::from_bytes(&value.reply_surb).map_err(|err| StorageError::CorruptedData {
details: format!("failed to recover the reply surb: {err}"),
})
}
}
@@ -33,6 +33,7 @@ where
self.backend.load_surb_storage().await
}
// this will have to get enabled after merging develop
pub async fn flush_on_shutdown(
mut self,
mem_state: CombinedReplyStorage,
@@ -49,6 +50,7 @@ where
shutdown.recv().await;
info!("PersistentReplyStorage is flushing all reply-related data to underlying storage");
info!("you MUST NOT forcefully shutdown now or you risk data corruption!");
if let Err(err) = self.backend.flush_surb_storage(&mem_state).await {
error!("failed to flush our reply-related data to the persistent storage: {err}")
} else {
@@ -5,7 +5,7 @@ use dashmap::iter::Iter;
use dashmap::DashMap;
use log::trace;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::anonymous_replies::ReplySurbWithKeyRotation;
use nym_sphinx::anonymous_replies::ReplySurb;
use std::collections::VecDeque;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
@@ -134,7 +134,7 @@ impl ReceivedReplySurbsMap {
&self,
target: &AnonymousSenderTag,
amount: usize,
) -> (Option<Vec<ReplySurbWithKeyRotation>>, usize) {
) -> (Option<Vec<ReplySurb>>, usize) {
if let Some(mut entry) = self.inner.data.get_mut(target) {
let surbs_left = entry.items_left();
if surbs_left < self.min_surb_threshold() + amount {
@@ -150,7 +150,7 @@ impl ReceivedReplySurbsMap {
pub fn get_reply_surb_ignoring_threshold(
&self,
target: &AnonymousSenderTag,
) -> Option<(Option<ReplySurbWithKeyRotation>, usize)> {
) -> Option<(Option<ReplySurb>, usize)> {
self.inner
.data
.get_mut(target)
@@ -160,7 +160,7 @@ impl ReceivedReplySurbsMap {
pub fn get_reply_surb(
&self,
target: &AnonymousSenderTag,
) -> Option<(Option<ReplySurbWithKeyRotation>, usize)> {
) -> Option<(Option<ReplySurb>, usize)> {
self.inner.data.get_mut(target).map(|mut entry| {
let surbs_left = entry.items_left();
if surbs_left < self.min_surb_threshold() {
@@ -171,7 +171,7 @@ impl ReceivedReplySurbsMap {
})
}
pub fn insert_surbs<I: IntoIterator<Item = ReplySurbWithKeyRotation>>(
pub fn insert_surbs<I: IntoIterator<Item = ReplySurb>>(
&self,
target: &AnonymousSenderTag,
surbs: I,
@@ -189,14 +189,14 @@ impl ReceivedReplySurbsMap {
pub struct ReceivedReplySurbs {
// in the future we'd probably want to put extra data here to indicate when the SURBs got received
// so we could invalidate entries from the previous key rotations
data: VecDeque<ReplySurbWithKeyRotation>,
data: VecDeque<ReplySurb>,
pending_reception: u32,
surbs_last_received_at_timestamp: i64,
}
impl ReceivedReplySurbs {
fn new(initial_surbs: VecDeque<ReplySurbWithKeyRotation>) -> Self {
fn new(initial_surbs: VecDeque<ReplySurb>) -> Self {
ReceivedReplySurbs {
data: initial_surbs,
pending_reception: 0,
@@ -206,7 +206,7 @@ impl ReceivedReplySurbs {
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
pub fn new_retrieved(
surbs: Vec<ReplySurbWithKeyRotation>,
surbs: Vec<ReplySurb>,
surbs_last_received_at_timestamp: i64,
) -> ReceivedReplySurbs {
ReceivedReplySurbs {
@@ -217,7 +217,7 @@ impl ReceivedReplySurbs {
}
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
pub fn surbs_ref(&self) -> &VecDeque<ReplySurbWithKeyRotation> {
pub fn surbs_ref(&self) -> &VecDeque<ReplySurb> {
&self.data
}
@@ -243,10 +243,7 @@ impl ReceivedReplySurbs {
self.pending_reception = 0;
}
pub fn get_reply_surbs(
&mut self,
amount: usize,
) -> (Option<Vec<ReplySurbWithKeyRotation>>, usize) {
pub fn get_reply_surbs(&mut self, amount: usize) -> (Option<Vec<ReplySurb>>, usize) {
if self.items_left() < amount {
(None, self.items_left())
} else {
@@ -255,11 +252,11 @@ impl ReceivedReplySurbs {
}
}
pub fn get_reply_surb(&mut self) -> (Option<ReplySurbWithKeyRotation>, usize) {
pub fn get_reply_surb(&mut self) -> (Option<ReplySurb>, usize) {
(self.pop_surb(), self.items_left())
}
fn pop_surb(&mut self) -> Option<ReplySurbWithKeyRotation> {
fn pop_surb(&mut self) -> Option<ReplySurb> {
self.data.pop_front()
}
@@ -268,10 +265,7 @@ impl ReceivedReplySurbs {
}
// realistically we're always going to be getting multiple surbs at once
pub fn insert_reply_surbs<I: IntoIterator<Item = ReplySurbWithKeyRotation>>(
&mut self,
surbs: I,
) {
pub fn insert_reply_surbs<I: IntoIterator<Item = ReplySurb>>(&mut self, surbs: I) {
let mut v = surbs.into_iter().collect::<VecDeque<_>>();
trace!("storing {} surbs in the storage", v.len());
self.data.append(&mut v);
@@ -21,8 +21,8 @@ use nym_crypto::asymmetric::ed25519;
use nym_gateway_requests::registration::handshake::client_handshake;
use nym_gateway_requests::{
BinaryRequest, ClientControlRequest, ClientRequest, GatewayProtocolVersionExt,
GatewayRequestsError, SensitiveServerResponse, ServerResponse, SharedGatewayKey,
SharedSymmetricKey, CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION, CURRENT_PROTOCOL_VERSION,
SensitiveServerResponse, ServerResponse, SharedGatewayKey, SharedSymmetricKey,
CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION, CURRENT_PROTOCOL_VERSION,
};
use nym_sphinx::forwarding::packet::MixPacket;
use nym_statistics_common::clients::connection::ConnectionStatsEvent;
@@ -662,7 +662,6 @@ impl<C, St> GatewayClient<C, St> {
let supports_aes_gcm_siv = gw_protocol.supports_aes256_gcm_siv();
let supports_auth_v2 = gw_protocol.supports_authenticate_v2();
let supports_key_rotation_info = gw_protocol.supports_key_rotation_packet();
if !supports_aes_gcm_siv {
warn!("this gateway is on an old version that doesn't support AES256-GCM-SIV");
@@ -670,9 +669,6 @@ impl<C, St> GatewayClient<C, St> {
if !supports_auth_v2 {
warn!("this gateway is on an old version that doesn't support authentication v2")
}
if !supports_key_rotation_info {
warn!("this gateway is on an old version that doesn't support key rotation packets")
}
if self.authenticated {
debug!("Already authenticated");
@@ -853,22 +849,6 @@ impl<C, St> GatewayClient<C, St> {
}
}
fn mix_packet_to_ws_message(&self, packet: MixPacket) -> Result<Message, GatewayRequestsError> {
// note: into_ws_message encrypts the requests and adds a MAC on it. Perhaps it should
// be more explicit in the naming?
let req = if self.negotiated_protocol.supports_key_rotation_packet() {
BinaryRequest::ForwardSphinxV2 { packet }
} else {
BinaryRequest::ForwardSphinx { packet }
};
req.into_ws_message(
self.shared_key
.as_ref()
.expect("no shared key present even though we're authenticated!"),
)
}
pub async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
@@ -897,7 +877,13 @@ impl<C, St> GatewayClient<C, St> {
let messages: Result<Vec<_>, _> = packets
.into_iter()
.map(|mix_packet| self.mix_packet_to_ws_message(mix_packet))
.map(|mix_packet| {
BinaryRequest::ForwardSphinx { packet: mix_packet }.into_ws_message(
self.shared_key
.as_ref()
.expect("no shared key present even though we're authenticated!"),
)
})
.collect();
if let Err(err) = self
@@ -963,8 +949,13 @@ impl<C, St> GatewayClient<C, St> {
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
let msg = self.mix_packet_to_ws_message(mix_packet)?;
// note: into_ws_message encrypts the requests and adds a MAC on it. Perhaps it should
// be more explicit in the naming?
let msg = BinaryRequest::ForwardSphinx { packet: mix_packet }.into_ws_message(
self.shared_key
.as_ref()
.expect("no shared key present even though we're authenticated!"),
)?;
self.send_with_reconnection_on_failure(msg).await
}
@@ -56,7 +56,7 @@ pub(crate) async fn connect_async(
}
.map_err(|err| GatewayClientError::NetworkConnectionFailed {
address: endpoint.to_owned(),
source: Box::new(tungstenite::Error::from(err)),
source: err.into(),
})?;
#[cfg(unix)]
@@ -72,7 +72,7 @@ pub(crate) async fn connect_async(
Err(err) => {
stream = Err(GatewayClientError::NetworkConnectionFailed {
address: endpoint.to_owned(),
source: Box::new(tungstenite::Error::from(err)),
source: err.into(),
});
continue;
}
@@ -83,6 +83,6 @@ pub(crate) async fn connect_async(
.await
.map_err(|error| GatewayClientError::NetworkConnectionFailed {
address: endpoint.to_owned(),
source: Box::new(error),
source: error,
})
}
+3 -12
View File
@@ -25,7 +25,7 @@ pub enum GatewayClientError {
RequestError(#[from] GatewayRequestsError),
#[error("There was a network error: {0}")]
NetworkError(Box<WsError>),
NetworkError(#[from] WsError),
#[error("failed to upgrade our shared key - the gateway sent malformed response")]
FatalKeyUpgradeFailure,
@@ -41,10 +41,7 @@ pub enum GatewayClientError {
NetworkErrorWasm(#[from] JsError),
#[error("connection failed: {address}: {source}")]
NetworkConnectionFailed {
address: String,
source: Box<WsError>,
},
NetworkConnectionFailed { address: String, source: WsError },
#[error("no socket address for endpoint: {address}")]
NoEndpointForConnection { address: String },
@@ -130,16 +127,10 @@ pub enum GatewayClientError {
ShutdownInProgress,
}
impl From<WsError> for GatewayClientError {
fn from(error: WsError) -> Self {
GatewayClientError::NetworkError(Box::new(error))
}
}
impl GatewayClientError {
pub fn is_closed_connection(&self) -> bool {
match self {
GatewayClientError::NetworkError(ws_err) => match ws_err.as_ref() {
GatewayClientError::NetworkError(ws_err) => match ws_err {
WsError::AlreadyClosed | WsError::ConnectionClosed => true,
WsError::Io(io_err) => matches!(
io_err.kind(),
+2 -2
View File
@@ -28,7 +28,7 @@ pub(crate) fn cleanup_socket_message(
msg: Option<Result<Message, WsError>>,
) -> Result<Message, GatewayClientError> {
match msg {
Some(msg) => msg.map_err(GatewayClientError::from),
Some(msg) => msg.map_err(GatewayClientError::NetworkError),
None => Err(GatewayClientError::ConnectionAbruptlyClosed),
}
}
@@ -39,7 +39,7 @@ pub(crate) fn cleanup_socket_messages(
match msgs {
Some(msgs) => msgs
.into_iter()
.map(|msg| msg.map_err(GatewayClientError::from))
.map(|msg| msg.map_err(GatewayClientError::NetworkError))
.collect(),
None => Err(GatewayClientError::ConnectionAbruptlyClosed),
}
+1 -6
View File
@@ -16,14 +16,9 @@ tokio-util = { workspace = true, features = ["codec"], optional = true }
tokio-stream = { workspace = true }
# internal
nym-noise = { path = "../../nymnoise" }
nym-sphinx = { path = "../../nymsphinx" }
nym-task = { path = "../../task", optional = true }
[features]
default = ["client"]
client = ["tokio-util", "nym-task", "tokio/net", "tokio/rt"]
[dev-dependencies]
nym-crypto = { path = "../../crypto" }
rand = { workspace = true }
client = ["tokio-util", "nym-task", "tokio/net", "tokio/rt"]
+25 -48
View File
@@ -3,11 +3,11 @@
use dashmap::DashMap;
use futures::StreamExt;
use nym_noise::config::NoiseConfig;
use nym_noise::upgrade_noise_initiator;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx::framing::codec::NymCodec;
use nym_sphinx::framing::packet::FramedNymPacket;
use nym_sphinx::params::PacketType;
use nym_sphinx::NymPacket;
use std::io;
use std::net::SocketAddr;
use std::ops::Deref;
@@ -49,19 +49,23 @@ impl Config {
pub trait SendWithoutResponse {
// Without response in this context means we will not listen for anything we might get back (not
// that we should get anything), including any possible io errors
fn send_without_response(&self, packet: MixPacket) -> io::Result<()>;
fn send_without_response(
&self,
address: NymNodeRoutingAddress,
packet: NymPacket,
packet_type: PacketType,
) -> io::Result<()>;
}
pub struct Client {
active_connections: ActiveConnections,
noise_config: NoiseConfig,
connections_count: Arc<AtomicUsize>,
config: Config,
}
#[derive(Default, Clone)]
pub struct ActiveConnections {
inner: Arc<DashMap<SocketAddr, ConnectionSender>>,
inner: Arc<DashMap<NymNodeRoutingAddress, ConnectionSender>>,
}
impl ActiveConnections {
@@ -78,7 +82,7 @@ impl ActiveConnections {
}
impl Deref for ActiveConnections {
type Target = DashMap<SocketAddr, ConnectionSender>;
type Target = DashMap<NymNodeRoutingAddress, ConnectionSender>;
fn deref(&self) -> &Self::Target {
&self.inner
}
@@ -100,7 +104,6 @@ impl ConnectionSender {
struct ManagedConnection {
address: SocketAddr,
noise_config: NoiseConfig,
message_receiver: ReceiverStream<FramedNymPacket>,
connection_timeout: Duration,
current_reconnection: Arc<AtomicU32>,
@@ -109,14 +112,12 @@ struct ManagedConnection {
impl ManagedConnection {
fn new(
address: SocketAddr,
noise_config: NoiseConfig,
message_receiver: mpsc::Receiver<FramedNymPacket>,
connection_timeout: Duration,
current_reconnection: Arc<AtomicU32>,
) -> Self {
ManagedConnection {
address,
noise_config,
message_receiver: ReceiverStream::new(message_receiver),
connection_timeout,
current_reconnection,
@@ -131,21 +132,9 @@ impl ManagedConnection {
Ok(stream_res) => match stream_res {
Ok(stream) => {
debug!("Managed to establish connection to {}", self.address);
let noise_stream =
match upgrade_noise_initiator(stream, &self.noise_config).await {
Ok(noise_stream) => noise_stream,
Err(err) => {
error!("Failed to perform Noise handshake with {address} - {err}");
// we failed to finish the noise handshake - increase reconnection attempt
self.current_reconnection.fetch_add(1, Ordering::SeqCst);
return;
}
};
// if we managed to connect AND do the noise handshake, reset the reconnection count (whatever it might have been)
// if we managed to connect, reset the reconnection count (whatever it might have been)
self.current_reconnection.store(0, Ordering::Release);
debug!("Noise initiator handshake completed for {:?}", address);
Framed::new(noise_stream, NymCodec)
Framed::new(stream, NymCodec)
}
Err(err) => {
debug!("failed to establish connection to {address} (err: {err})",);
@@ -178,14 +167,9 @@ impl ManagedConnection {
}
impl Client {
pub fn new(
config: Config,
noise_config: NoiseConfig,
connections_count: Arc<AtomicUsize>,
) -> Client {
pub fn new(config: Config, connections_count: Arc<AtomicUsize>) -> Client {
Client {
active_connections: Default::default(),
noise_config,
connections_count,
config,
}
@@ -212,7 +196,7 @@ impl Client {
}
}
fn make_connection(&self, address: SocketAddr, pending_packet: FramedNymPacket) {
fn make_connection(&self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
let (sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
// this CAN'T fail because we just created the channel which has a non-zero capacity
@@ -240,7 +224,6 @@ impl Client {
let initial_connection_timeout = self.config.initial_connection_timeout;
let connections_count = self.connections_count.clone();
let noise_config = self.noise_config.clone();
tokio::spawn(async move {
// before executing the manager, wait for what was specified, if anything
if let Some(backoff) = backoff {
@@ -250,8 +233,7 @@ impl Client {
connections_count.fetch_add(1, Ordering::SeqCst);
ManagedConnection::new(
address,
noise_config,
address.into(),
receiver,
initial_connection_timeout,
current_reconnection_attempt,
@@ -264,14 +246,18 @@ impl Client {
}
impl SendWithoutResponse for Client {
fn send_without_response(&self, packet: MixPacket) -> io::Result<()> {
let address = packet.next_hop_address();
trace!("Sending packet to {address}");
let framed_packet = FramedNymPacket::from(packet);
fn send_without_response(
&self,
address: NymNodeRoutingAddress,
packet: NymPacket,
packet_type: PacketType,
) -> io::Result<()> {
trace!("Sending packet to {address:?}");
let framed_packet = FramedNymPacket::new(packet, packet_type);
let Some(sender) = self.active_connections.get_mut(&address) else {
// there was never a connection to begin with
debug!("establishing initial connection to {address}");
debug!("establishing initial connection to {}", address);
// it's not a 'big' error, but we did not manage to send the packet, but queue the packet
// for sending for as soon as the connection is created
self.make_connection(address, framed_packet);
@@ -316,12 +302,8 @@ impl SendWithoutResponse for Client {
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::x25519;
use nym_noise::config::NoiseNetworkView;
use rand::rngs::OsRng;
fn dummy_client() -> Client {
let mut rng = OsRng; //for test only, so we don't care if rng source isn't crypto grade
Client::new(
Config {
initial_reconnection_backoff: Duration::from_millis(10_000),
@@ -329,11 +311,6 @@ mod tests {
initial_connection_timeout: Duration::from_millis(1_500),
maximum_connection_buffer_size: 128,
},
NoiseConfig::new(
Arc::new(x25519::KeyPair::new(&mut rng)),
NoiseNetworkView::new_empty(),
Duration::from_millis(1_500),
),
Default::default(),
)
}
@@ -19,7 +19,6 @@ nym-vesting-contract-common = { path = "../../cosmwasm-smart-contracts/vesting-c
nym-ecash-contract-common = { path = "../../cosmwasm-smart-contracts/ecash-contract" }
nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
nym-performance-contract-common = { path = "../../cosmwasm-smart-contracts/nym-performance-contract" }
nym-serde-helpers = { path = "../../serde-helpers", features = ["hex", "base64"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
@@ -16,8 +16,8 @@ async fn main() {
let prefix = "n";
let denom: Denom = "unym".parse().unwrap();
let signer_mnemonic: bip39::Mnemonic = "<MNEMONIC WITH FUNDS HERE>".parse().unwrap();
let validator = "https://rpc.sandbox.nymtech.net";
let to_address: AccountId = "n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa".parse().unwrap();
let validator = "https://qwerty-validator.qa.nymte.ch";
let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap();
let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, signer_mnemonic);
let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone();
+84 -127
View File
@@ -25,9 +25,7 @@ use nym_api_requests::models::{
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::{
NodesByAddressesResponse, SemiSkimmedNodesWithMetadata, SkimmedNode, SkimmedNodesWithMetadata,
};
use nym_api_requests::nym_nodes::{NodesByAddressesResponse, SkimmedNode};
use nym_coconut_dkg_common::types::EpochId;
use nym_http_api_client::UserAgent;
use nym_mixnet_contract_common::EpochRewardedSet;
@@ -48,46 +46,6 @@ use crate::rpc::http_client;
#[cfg(feature = "http-client")]
use crate::{DirectSigningHttpRpcValidatorClient, HttpRpcClient, QueryHttpRpcValidatorClient};
// a simple helper macro to define to repeatedly call a paged query until a full response is constructed
macro_rules! collect_paged_skimmed_v2 {
( $self:ident, $f: ident ) => {{
// unroll first loop iteration in order to obtain the metadata
let mut page = 0;
let res = $self
.nym_api
.$f(false, Some(page), None, $self.use_bincode)
.await?;
let mut nodes = res.nodes.data;
let metadata = res.metadata;
if res.nodes.pagination.total == nodes.len() {
return Ok(SkimmedNodesWithMetadata::new(nodes, metadata));
}
page += 1;
loop {
let mut res = $self
.nym_api
.$f(false, Some(page), None, $self.use_bincode)
.await?;
if metadata != res.metadata {
return Err(ValidatorClientError::InconsistentPagedMetadata);
}
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(SkimmedNodesWithMetadata::new(nodes, metadata))
}};
}
#[must_use]
#[derive(Debug, Clone)]
pub struct Config {
@@ -242,11 +200,11 @@ impl<C, S> Client<C, S> {
#[allow(deprecated)]
impl<C, S> Client<C, S> {
pub fn api_url(&self) -> &Url {
self.nym_api.current_url().as_ref()
self.nym_api.current_url()
}
pub fn change_nym_api(&mut self, new_endpoint: Url) {
self.nym_api.change_base_urls(vec![new_endpoint.into()])
self.nym_api.change_base_url(new_endpoint)
}
#[deprecated]
@@ -444,11 +402,11 @@ impl NymApiClient {
}
pub fn api_url(&self) -> &Url {
self.nym_api.current_url().as_ref()
self.nym_api.current_url()
}
pub fn change_nym_api(&mut self, new_endpoint: Url) {
self.nym_api.change_base_urls(vec![new_endpoint.into()]);
self.nym_api.change_base_url(new_endpoint);
}
#[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes instead")]
@@ -467,93 +425,17 @@ impl NymApiClient {
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
#[deprecated(note = "use get_all_basic_entry_assigned_nodes_with_metadata instead")]
pub async fn get_all_basic_entry_assigned_nodes(
&self,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
self.get_all_basic_entry_assigned_nodes_v2()
.await
.map(|res| res.nodes)
}
pub async fn get_all_basic_entry_assigned_nodes_v2(
&self,
) -> Result<SkimmedNodesWithMetadata, ValidatorClientError> {
collect_paged_skimmed_v2!(self, get_basic_entry_assigned_nodes_v2)
}
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes_with_metadata instead")]
pub async fn get_all_basic_active_mixing_assigned_nodes(
&self,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
self.get_all_basic_active_mixing_assigned_nodes_with_metadata()
.await
.map(|res| res.nodes)
}
pub async fn get_all_basic_active_mixing_assigned_nodes_with_metadata(
&self,
) -> Result<SkimmedNodesWithMetadata, ValidatorClientError> {
collect_paged_skimmed_v2!(self, get_basic_active_mixing_assigned_nodes_v2)
}
/// retrieve basic information for nodes are capable of operating as a mixnode
/// this includes legacy mixnodes and nym-nodes
#[deprecated(note = "use get_all_basic_mixing_capable_nodes_with_metadata instead")]
pub async fn get_all_basic_mixing_capable_nodes(
&self,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
self.get_all_basic_mixing_capable_nodes_with_metadata()
.await
.map(|res| res.nodes)
}
pub async fn get_all_basic_mixing_capable_nodes_with_metadata(
&self,
) -> Result<SkimmedNodesWithMetadata, ValidatorClientError> {
collect_paged_skimmed_v2!(self, get_basic_mixing_capable_nodes_v2)
}
/// retrieve basic information for all bonded nodes on the network
#[deprecated(note = "use get_all_basic_nodes_with_metadata instead")]
pub async fn get_all_basic_nodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
self.get_all_basic_nodes_with_metadata()
.await
.map(|res| res.nodes)
}
pub async fn get_all_basic_nodes_with_metadata(
&self,
) -> Result<SkimmedNodesWithMetadata, ValidatorClientError> {
collect_paged_skimmed_v2!(self, get_basic_nodes_v2)
}
/// retrieve expanded information for all bonded nodes on the network
pub async fn get_all_expanded_nodes(
&self,
) -> Result<SemiSkimmedNodesWithMetadata, ValidatorClientError> {
// Unroll the first iteration to get the metadata
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let res = self
.nym_api
.get_expanded_nodes(false, Some(page), None)
.await?;
let mut nodes = res.nodes.data;
let metadata = res.metadata;
if res.nodes.pagination.total == nodes.len() {
return Ok(SemiSkimmedNodesWithMetadata::new(nodes, metadata));
}
page += 1;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_expanded_nodes(false, Some(page), None)
.get_basic_entry_assigned_nodes(false, Some(page), None, self.use_bincode)
.await?;
nodes.append(&mut res.nodes.data);
@@ -564,7 +446,82 @@ impl NymApiClient {
}
}
Ok(SemiSkimmedNodesWithMetadata::new(nodes, metadata))
Ok(nodes)
}
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_active_mixing_assigned_nodes(
&self,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_basic_active_mixing_assigned_nodes(false, Some(page), None, self.use_bincode)
.await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(nodes)
}
/// retrieve basic information for nodes are capable of operating as a mixnode
/// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_mixing_capable_nodes(
&self,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_basic_mixing_capable_nodes(false, Some(page), None, self.use_bincode)
.await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(nodes)
}
/// retrieve basic information for all bonded nodes on the network
pub async fn get_all_basic_nodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_basic_nodes(false, Some(page), None, self.use_bincode)
.await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(nodes)
}
pub async fn health(&self) -> Result<ApiHealthResponse, ValidatorClientError> {
@@ -22,9 +22,6 @@ pub enum ValidatorClientError {
#[error("nyxd request failed: {0}")]
NyxdError(#[from] crate::nyxd::error::NyxdError),
#[error("the response metadata has changed between pages")]
InconsistentPagedMetadata,
#[error("No validator API url has been provided")]
NoAPIUrlAvailable,
}
@@ -14,12 +14,11 @@ use nym_api_requests::ecash::models::{
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{
AnnotationResponse, ApiHealthResponse, BinaryBuildInformationOwned, ChainStatusResponse,
KeyRotationInfoResponse, LegacyDescribedMixNode, NodePerformanceResponse, NodeRefreshBody,
NymNodeDescription, PerformanceHistoryResponse, RewardedSetResponse,
LegacyDescribedMixNode, NodePerformanceResponse, NodeRefreshBody, NymNodeDescription,
PerformanceHistoryResponse, RewardedSetResponse,
};
use nym_api_requests::nym_nodes::{
NodesByAddressesRequestBody, NodesByAddressesResponse, PaginatedCachedNodesResponseV1,
PaginatedCachedNodesResponseV2,
NodesByAddressesRequestBody, NodesByAddressesResponse, PaginatedCachedNodesResponse,
};
use nym_api_requests::pagination::PaginatedResponse;
pub use nym_api_requests::{
@@ -35,7 +34,7 @@ pub use nym_api_requests::{
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
},
nym_nodes::{CachedNodesResponse, SemiSkimmedNode, SkimmedNode},
nym_nodes::{CachedNodesResponse, SkimmedNode},
NymNetworkDetailsResponse,
};
use nym_contracts_common::IdentityKey;
@@ -63,7 +62,7 @@ pub trait NymApiClientExt: ApiClient {
async fn health(&self) -> Result<ApiHealthResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::API_STATUS_ROUTES,
routes::HEALTH,
],
@@ -76,7 +75,7 @@ pub trait NymApiClientExt: ApiClient {
async fn build_information(&self) -> Result<BinaryBuildInformationOwned, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::API_STATUS_ROUTES,
routes::BUILD_INFORMATION,
],
@@ -88,7 +87,7 @@ pub trait NymApiClientExt: ApiClient {
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(&[routes::V1_API_VERSION, routes::MIXNODES], NO_PARAMS)
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await
}
@@ -97,7 +96,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::MIXNODES,
routes::DETAILED,
@@ -112,7 +111,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::GATEWAYS,
routes::DETAILED,
@@ -129,7 +128,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::GATEWAYS,
routes::DETAILED_UNFILTERED,
@@ -146,7 +145,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::MIXNODES,
routes::DETAILED_UNFILTERED,
@@ -159,7 +158,7 @@ pub trait NymApiClientExt: ApiClient {
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.get_json(&[routes::V1_API_VERSION, routes::GATEWAYS], NO_PARAMS)
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
}
@@ -167,7 +166,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> {
self.get_json(
&[routes::V1_API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
NO_PARAMS,
)
.await
@@ -177,7 +176,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> {
self.get_json(
&[routes::V1_API_VERSION, routes::MIXNODES, routes::DESCRIBED],
&[routes::API_VERSION, routes::MIXNODES, routes::DESCRIBED],
NO_PARAMS,
)
.await
@@ -202,7 +201,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_PERFORMANCE_HISTORY,
&*node_id.to_string(),
@@ -230,7 +229,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_DESCRIBED,
],
@@ -257,7 +256,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_BONDED,
],
@@ -271,7 +270,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_basic_mixnodes(&self) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"mixnodes",
@@ -287,7 +286,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_basic_gateways(&self) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"gateways",
@@ -302,7 +301,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_rewarded_set(&self) -> Result<RewardedSetResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_REWARDED_SET,
],
@@ -313,7 +312,6 @@ pub trait NymApiClientExt: ApiClient {
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
#[deprecated(note = "use get_basic_entry_assigned_nodes_v2")]
#[instrument(level = "debug", skip(self))]
async fn get_basic_entry_assigned_nodes(
&self,
@@ -321,7 +319,7 @@ pub trait NymApiClientExt: ApiClient {
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV1<SkimmedNode>, NymAPIError> {
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
@@ -342,49 +340,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_response(
&[
routes::V1_API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
"entry-gateways",
"all",
],
&params,
)
.await
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_basic_entry_assigned_nodes_v2(
&self,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV2<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
if use_bincode {
params.push(("output", "bincode".to_string()))
}
self.get_response(
&[
routes::V2_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
@@ -398,7 +354,6 @@ pub trait NymApiClientExt: ApiClient {
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[deprecated(note = "use get_basic_active_mixing_assigned_nodes_v2")]
#[instrument(level = "debug", skip(self))]
async fn get_basic_active_mixing_assigned_nodes(
&self,
@@ -406,7 +361,7 @@ pub trait NymApiClientExt: ApiClient {
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV1<SkimmedNode>, NymAPIError> {
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
@@ -427,7 +382,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_response(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
@@ -442,56 +397,13 @@ pub trait NymApiClientExt: ApiClient {
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_basic_active_mixing_assigned_nodes_v2(
&self,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV2<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
if use_bincode {
params.push(("output", "bincode".to_string()))
}
self.get_response(
&[
routes::V2_API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
"mixnodes",
"active",
],
&params,
)
.await
}
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[deprecated(note = "use get_basic_mixing_capable_nodes_v2")]
#[instrument(level = "debug", skip(self))]
async fn get_basic_mixing_capable_nodes(
&self,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV1<SkimmedNode>, NymAPIError> {
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
@@ -512,7 +424,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_response(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
@@ -524,49 +436,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_basic_mixing_capable_nodes_v2(
&self,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV2<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
if use_bincode {
params.push(("output", "bincode".to_string()))
}
self.get_response(
&[
routes::V2_API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
"mixnodes",
"all",
],
&params,
)
.await
}
#[deprecated(note = "use get_basic_nodes_v2")]
#[instrument(level = "debug", skip(self))]
async fn get_basic_nodes(
&self,
@@ -574,7 +443,7 @@ pub trait NymApiClientExt: ApiClient {
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV1<SkimmedNode>, NymAPIError> {
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
@@ -595,7 +464,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_response(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
@@ -605,82 +474,11 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_basic_nodes_v2(
&self,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
use_bincode: bool,
) -> Result<PaginatedCachedNodesResponseV2<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
if use_bincode {
params.push(("output", "bincode".to_string()))
}
self.get_response(
&[
routes::V2_API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
],
&params,
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_expanded_nodes(
&self,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponseV2<SemiSkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
self.get_json(
&[
routes::V2_API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"semi-skimmed",
],
&params,
)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::V1_API_VERSION, routes::MIXNODES, routes::ACTIVE],
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
NO_PARAMS,
)
.await
@@ -691,7 +489,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::MIXNODES,
routes::ACTIVE,
@@ -706,7 +504,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::V1_API_VERSION, routes::MIXNODES, routes::REWARDED],
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
NO_PARAMS,
)
.await
@@ -720,7 +518,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::MIXNODE,
&mix_id.to_string(),
@@ -739,7 +537,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<GatewayStatusReportResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::GATEWAY,
identity,
@@ -758,7 +556,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::MIXNODE,
&mix_id.to_string(),
@@ -777,7 +575,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<GatewayUptimeHistoryResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::GATEWAY,
identity,
@@ -795,7 +593,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS,
routes::MIXNODES,
routes::REWARDED,
@@ -816,7 +614,7 @@ pub trait NymApiClientExt: ApiClient {
if let Some(since) = since {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::GATEWAY,
identity,
@@ -828,7 +626,7 @@ pub trait NymApiClientExt: ApiClient {
} else {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::GATEWAY,
identity,
@@ -849,7 +647,7 @@ pub trait NymApiClientExt: ApiClient {
if let Some(since) = since {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -861,7 +659,7 @@ pub trait NymApiClientExt: ApiClient {
} else {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -881,7 +679,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<MixnodeStatusResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -900,7 +698,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<RewardEstimationResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -920,7 +718,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<RewardEstimationResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -940,7 +738,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<StakeSaturationResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -960,7 +758,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<nym_api_requests::models::InclusionProbabilityResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -978,7 +776,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<NodePerformanceResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_PERFORMANCE,
&node_id.to_string(),
@@ -994,7 +792,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<AnnotationResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_ANNOTATION,
&node_id.to_string(),
@@ -1008,7 +806,7 @@ pub trait NymApiClientExt: ApiClient {
async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
@@ -1023,11 +821,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::MIXNODES,
routes::BLACKLISTED,
],
&[routes::API_VERSION, routes::MIXNODES, routes::BLACKLISTED],
NO_PARAMS,
)
.await
@@ -1037,11 +831,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::GATEWAYS,
routes::BLACKLISTED,
],
&[routes::API_VERSION, routes::GATEWAYS, routes::BLACKLISTED],
NO_PARAMS,
)
.await
@@ -1054,7 +844,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<BlindedSignatureResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::ECASH_BLIND_SIGN,
],
@@ -1071,7 +861,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<EcashTicketVerificationResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::VERIFY_ECASH_TICKET,
],
@@ -1088,7 +878,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<EcashBatchTicketRedemptionResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::BATCH_REDEEM_ECASH_TICKETS,
],
@@ -1113,7 +903,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::PARTIAL_EXPIRATION_DATE_SIGNATURES,
],
@@ -1134,7 +924,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::PARTIAL_COIN_INDICES_SIGNATURES,
],
@@ -1158,7 +948,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::GLOBAL_EXPIRATION_DATE_SIGNATURES,
],
@@ -1179,7 +969,7 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::GLOBAL_COIN_INDICES_SIGNATURES,
],
@@ -1199,7 +989,7 @@ pub trait NymApiClientExt: ApiClient {
};
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
ecash::MASTER_VERIFICATION_KEY,
],
@@ -1215,7 +1005,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<(), NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_REFRESH_DESCRIBED,
],
@@ -1232,7 +1022,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<IssuedTicketbooksForResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::ECASH_ISSUED_TICKETBOOKS_FOR,
&expiration_date.to_string(),
@@ -1249,7 +1039,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<IssuedTicketbooksForCountResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::ECASH_ISSUED_TICKETBOOKS_FOR_COUNT,
&expiration_date.to_string(),
@@ -1266,7 +1056,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<IssuedTicketbooksChallengeCommitmentResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::ECASH_ISSUED_TICKETBOOKS_CHALLENGE_COMMITMENT,
],
@@ -1283,7 +1073,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<IssuedTicketbooksDataResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::ECASH_ISSUED_TICKETBOOKS_DATA,
],
@@ -1299,7 +1089,7 @@ pub trait NymApiClientExt: ApiClient {
) -> Result<NodesByAddressesResponse, NymAPIError> {
self.post_json(
&[
routes::V1_API_VERSION,
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
routes::nym_nodes::BY_ADDRESSES,
@@ -1313,7 +1103,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_network_details(&self) -> Result<NymNetworkDetailsResponse, NymAPIError> {
self.get_json(
&[routes::V1_API_VERSION, routes::NETWORK, routes::DETAILS],
&[routes::API_VERSION, routes::NETWORK, routes::DETAILS],
NO_PARAMS,
)
.await
@@ -1322,24 +1112,7 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_chain_status(&self) -> Result<ChainStatusResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::NETWORK,
routes::CHAIN_STATUS,
],
NO_PARAMS,
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_key_rotation_info(&self) -> Result<KeyRotationInfoResponse, NymAPIError> {
self.get_json(
&[
routes::V1_API_VERSION,
routes::EPOCH,
routes::KEY_ROTATION_INFO,
],
&[routes::API_VERSION, routes::NETWORK, routes::CHAIN_STATUS],
NO_PARAMS,
)
.await
@@ -1,8 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub const V1_API_VERSION: &str = "v1";
pub const V2_API_VERSION: &str = "v2";
use nym_network_defaults::NYM_API_VERSION;
pub const API_VERSION: &str = NYM_API_VERSION;
pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways";
pub const DESCRIBED: &str = "described";
@@ -78,11 +79,3 @@ pub const SERVICE_PROVIDERS: &str = "services";
pub const DETAILS: &str = "details";
pub const CHAIN_STATUS: &str = "chain-status";
pub const NETWORK: &str = "network";
pub const EPOCH: &str = "epoch";
pub use epoch_routes::*;
pub mod epoch_routes {
pub const CURRENT: &str = "current";
pub const KEY_ROTATION_INFO: &str = "key-rotation-info";
}
@@ -12,8 +12,8 @@ use nym_mixnet_contract_common::gateway::{PreassignedGatewayIdsResponse, Preassi
use nym_mixnet_contract_common::nym_node::{
EpochAssignmentResponse, NodeDetailsByIdentityResponse, NodeDetailsResponse,
NodeOwnershipResponse, NodeRewardingDetailsResponse, PagedNymNodeBondsResponse,
PagedNymNodeDetailsResponse, PagedUnbondedNymNodesResponse, RewardedSetMetadata, Role,
RolesMetadataResponse, StakeSaturationResponse, UnbondedNodeResponse, UnbondedNymNode,
PagedNymNodeDetailsResponse, PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse,
StakeSaturationResponse, UnbondedNodeResponse, UnbondedNymNode,
};
use nym_mixnet_contract_common::reward_params::WorkFactor;
use nym_mixnet_contract_common::{
@@ -28,12 +28,12 @@ use nym_mixnet_contract_common::{
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
CurrentNymNodeVersionResponse, Delegation, EpochEventId, EpochRewardedSet, EpochStatus,
GatewayBond, GatewayBondResponse, GatewayOwnershipResponse, HistoricalNymNodeVersionEntry,
IdentityKey, IdentityKeyRef, IntervalEventId, KeyRotationIdResponse, KeyRotationState,
MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse,
MixnodeDetailsResponse, NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
NymNodeVersionHistoryResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedGatewayResponse, PagedMixnodeBondsResponse, PagedNodeDelegationsResponse,
PendingEpochEvent, PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond, MixNodeDetails,
MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, NodeId,
NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, NymNodeVersionHistoryResponse,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
PendingIntervalEventResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
RewardedSet, UnbondedMixnode,
};
@@ -546,16 +546,6 @@ pub trait MixnetQueryClient {
})
.await
}
async fn get_key_rotation_state(&self) -> Result<KeyRotationState, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetKeyRotationState {})
.await
}
async fn get_key_rotation_id(&self) -> Result<KeyRotationIdResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetKeyRotationId {})
.await
}
}
// extension trait to the query client to deal with the paged queries
@@ -683,20 +673,12 @@ pub trait MixnetQueryClientExt: MixnetQueryClient {
async fn get_rewarded_set(&self) -> Result<EpochRewardedSet, NyxdError> {
let error_response = |message| Err(NyxdError::extension_query_failure("mixnet", message));
// bypass for catch 22 for fresh contracts. we can't refresh cache because there's no rewarded set,
// but we can't set the rewarded set because we didn't refresh the cache
let metadata = self.get_rewarded_set_metadata().await?;
let is_default = metadata.metadata == RewardedSetMetadata::default();
if !metadata.metadata.fully_assigned && !is_default {
if !metadata.metadata.fully_assigned {
return error_response("the rewarded set hasn't been fully assigned for this epoch");
}
let expected_epoch_id = metadata.metadata.epoch_id;
if is_default {
return Ok(Default::default());
}
// if we have to query those things more frequently, we could do it concurrently,
// but as it stands now, it happens so infrequently it might as well be sequential
let entry = self.get_role_assignment(Role::EntryGateway).await?;
@@ -973,8 +955,6 @@ mod tests {
QueryMsg::GetNymNodeVersionHistory { limit, start_after } => client
.get_nym_node_version_history_paged(start_after, limit)
.ignore(),
QueryMsg::GetKeyRotationState {} => client.get_key_rotation_state().ignore(),
QueryMsg::GetKeyRotationId {} => client.get_key_rotation_id().ignore(),
}
}
}
@@ -13,7 +13,6 @@ pub mod ecash_query_client;
pub mod group_query_client;
pub mod mixnet_query_client;
pub mod multisig_query_client;
pub mod performance_query_client;
pub mod vesting_query_client;
// signing clients
@@ -22,7 +21,6 @@ pub mod ecash_signing_client;
pub mod group_signing_client;
pub mod mixnet_signing_client;
pub mod multisig_signing_client;
pub mod performance_signing_client;
pub mod vesting_signing_client;
// re-export query traits
@@ -31,7 +29,6 @@ pub use ecash_query_client::{EcashQueryClient, PagedEcashQueryClient};
pub use group_query_client::{GroupQueryClient, PagedGroupQueryClient};
pub use mixnet_query_client::{MixnetQueryClient, PagedMixnetQueryClient};
pub use multisig_query_client::{MultisigQueryClient, PagedMultisigQueryClient};
pub use performance_query_client::{PagedPerformanceQueryClient, PerformanceQueryClient};
pub use vesting_query_client::{PagedVestingQueryClient, VestingQueryClient};
// re-export signing traits
@@ -40,7 +37,6 @@ pub use ecash_signing_client::EcashSigningClient;
pub use group_signing_client::GroupSigningClient;
pub use mixnet_signing_client::MixnetSigningClient;
pub use multisig_signing_client::MultisigSigningClient;
pub use performance_signing_client::PerformanceSigningClient;
pub use vesting_signing_client::VestingSigningClient;
// helper for providing blanket implementation for query clients
@@ -48,7 +44,6 @@ pub trait NymContractsProvider {
// main
fn mixnet_contract_address(&self) -> Option<&AccountId>;
fn vesting_contract_address(&self) -> Option<&AccountId>;
fn performance_contract_address(&self) -> Option<&AccountId>;
// coconut-related
fn ecash_contract_address(&self) -> Option<&AccountId>;
@@ -61,7 +56,6 @@ pub trait NymContractsProvider {
pub struct TypedNymContracts {
pub mixnet_contract_address: Option<AccountId>,
pub vesting_contract_address: Option<AccountId>,
pub performance_contract_address: Option<AccountId>,
pub ecash_contract_address: Option<AccountId>,
pub group_contract_address: Option<AccountId>,
@@ -82,10 +76,6 @@ impl TryFrom<NymContracts> for TypedNymContracts {
.vesting_contract_address
.map(|addr| addr.parse())
.transpose()?,
performance_contract_address: value
.performance_contract_address
.map(|addr| addr.parse())
.transpose()?,
ecash_contract_address: value
.ecash_contract_address
.map(|addr| addr.parse())
@@ -1,271 +0,0 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::collect_paged;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use serde::Deserialize;
pub use nym_performance_contract_common::{
msg::QueryMsg as PerformanceQueryMsg, types::NetworkMonitorResponse, EpochId,
EpochMeasurementsPagedResponse, EpochNodePerformance, EpochPerformancePagedResponse,
FullHistoricalPerformancePagedResponse, HistoricalPerformance, LastSubmission,
NetworkMonitorInformation, NetworkMonitorsPagedResponse, NodeId, NodeMeasurement,
NodeMeasurementsResponse, NodePerformance, NodePerformancePagedResponse,
NodePerformanceResponse, RetiredNetworkMonitor, RetiredNetworkMonitorsPagedResponse,
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PerformanceQueryClient {
async fn query_performance_contract<T>(
&self,
query: PerformanceQueryMsg,
) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn admin(&self) -> Result<cw_controllers::AdminResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::Admin {})
.await
}
async fn get_node_performance(
&self,
epoch_id: EpochId,
node_id: NodeId,
) -> Result<NodePerformanceResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::NodePerformance { epoch_id, node_id })
.await
}
async fn get_node_performance_paged(
&self,
node_id: NodeId,
start_after: Option<EpochId>,
limit: Option<u32>,
) -> Result<NodePerformancePagedResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::NodePerformancePaged {
node_id,
start_after,
limit,
})
.await
}
async fn get_node_measurements(
&self,
epoch_id: EpochId,
node_id: NodeId,
) -> Result<NodeMeasurementsResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::NodeMeasurements { epoch_id, node_id })
.await
}
async fn get_epoch_measurements_paged(
&self,
epoch_id: EpochId,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<EpochMeasurementsPagedResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::EpochMeasurementsPaged {
epoch_id,
start_after,
limit,
})
.await
}
async fn get_epoch_performance_paged(
&self,
epoch_id: EpochId,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<EpochPerformancePagedResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::EpochPerformancePaged {
epoch_id,
start_after,
limit,
})
.await
}
async fn get_full_historical_performance_paged(
&self,
start_after: Option<(EpochId, NodeId)>,
limit: Option<u32>,
) -> Result<FullHistoricalPerformancePagedResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::FullHistoricalPerformancePaged {
start_after,
limit,
})
.await
}
async fn get_network_monitor(
&self,
address: &AccountId,
) -> Result<NetworkMonitorResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::NetworkMonitor {
address: address.to_string(),
})
.await
}
async fn get_network_monitors_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<NetworkMonitorsPagedResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::NetworkMonitorsPaged {
start_after,
limit,
})
.await
}
async fn get_retired_network_monitors_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<RetiredNetworkMonitorsPagedResponse, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::RetiredNetworkMonitorsPaged {
start_after,
limit,
})
.await
}
async fn get_last_submission(&self) -> Result<LastSubmission, NyxdError> {
self.query_performance_contract(PerformanceQueryMsg::LastSubmittedMeasurement {})
.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 PagedPerformanceQueryClient: PerformanceQueryClient {
async fn get_all_node_performance(
&self,
node_id: NodeId,
) -> Result<Vec<EpochNodePerformance>, NyxdError> {
collect_paged!(self, get_node_performance_paged, performance, node_id)
}
async fn get_all_epoch_measurements(
&self,
node_id: NodeId,
) -> Result<Vec<NodeMeasurement>, NyxdError> {
collect_paged!(self, get_epoch_measurements_paged, measurements, node_id)
}
async fn get_all_epoch_performance(
&self,
epoch_id: EpochId,
) -> Result<Vec<NodePerformance>, NyxdError> {
collect_paged!(self, get_epoch_performance_paged, performance, epoch_id)
}
async fn get_all_full_historical_performance(
&self,
) -> Result<Vec<HistoricalPerformance>, NyxdError> {
collect_paged!(self, get_full_historical_performance_paged, performance)
}
async fn get_all_network_monitors(&self) -> Result<Vec<NetworkMonitorInformation>, NyxdError> {
collect_paged!(self, get_network_monitors_paged, info)
}
async fn get_all_retired_network_monitors(
&self,
) -> Result<Vec<RetiredNetworkMonitor>, NyxdError> {
collect_paged!(self, get_retired_network_monitors_paged, info)
}
}
#[async_trait]
impl<T> PagedPerformanceQueryClient for T where T: PerformanceQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> PerformanceQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_performance_contract<T>(
&self,
query: PerformanceQueryMsg,
) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let performance_contract_address = &self
.performance_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("performance contract"))?;
self.query_contract_smart(performance_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
use nym_performance_contract_common::QueryMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_query_variants_are_covered<C: PerformanceQueryClient + Send + Sync>(
client: C,
msg: PerformanceQueryMsg,
) {
match msg {
PerformanceQueryMsg::Admin {} => client.admin().ignore(),
PerformanceQueryMsg::NodePerformance { epoch_id, node_id } => {
client.get_node_performance(epoch_id, node_id).ignore()
}
PerformanceQueryMsg::NodePerformancePaged {
node_id,
start_after,
limit,
} => client
.get_node_performance_paged(node_id, start_after, limit)
.ignore(),
PerformanceQueryMsg::NodeMeasurements { epoch_id, node_id } => {
client.get_node_measurements(epoch_id, node_id).ignore()
}
PerformanceQueryMsg::EpochMeasurementsPaged {
epoch_id,
start_after,
limit,
} => client
.get_epoch_measurements_paged(epoch_id, start_after, limit)
.ignore(),
PerformanceQueryMsg::EpochPerformancePaged {
epoch_id,
start_after,
limit,
} => client
.get_epoch_performance_paged(epoch_id, start_after, limit)
.ignore(),
PerformanceQueryMsg::FullHistoricalPerformancePaged { start_after, limit } => client
.get_full_historical_performance_paged(start_after, limit)
.ignore(),
PerformanceQueryMsg::NetworkMonitor { address } => client
.get_network_monitor(&address.parse().unwrap())
.ignore(),
PerformanceQueryMsg::NetworkMonitorsPaged { start_after, limit } => client
.get_network_monitors_paged(start_after, limit)
.ignore(),
PerformanceQueryMsg::RetiredNetworkMonitorsPaged { start_after, limit } => client
.get_retired_network_monitors_paged(start_after, limit)
.ignore(),
QueryMsg::LastSubmittedMeasurement {} => client.get_last_submission().ignore(),
};
}
}
@@ -1,217 +0,0 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::coin::Coin;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
use crate::nyxd::cosmwasm_client::ContractResponseData;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Fee, SigningCosmWasmClient};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use nym_performance_contract_common::{
EpochId, ExecuteMsg as PerformanceExecuteMsg, NodeId, NodePerformance,
RemoveEpochMeasurementsResponse,
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PerformanceSigningClient {
async fn execute_performance_contract(
&self,
fee: Option<Fee>,
msg: PerformanceExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn update_admin(
&self,
admin: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::UpdateAdmin { admin },
"PerformanceContract::UpdateAdmin".to_string(),
vec![],
)
.await
}
async fn submit_performance(
&self,
epoch: EpochId,
data: NodePerformance,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::Submit { epoch, data },
"PerformanceContract::Submit".to_string(),
vec![],
)
.await
}
async fn batch_submit_performance(
&self,
epoch: EpochId,
data: Vec<NodePerformance>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::BatchSubmit { epoch, data },
"PerformanceContract::BatchSubmit".to_string(),
vec![],
)
.await
}
async fn authorise_network_monitor(
&self,
address: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::AuthoriseNetworkMonitor { address },
"PerformanceContract::AuthoriseNetworkMonitor".to_string(),
vec![],
)
.await
}
async fn retire_network_monitor(
&self,
address: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::RetireNetworkMonitor { address },
"PerformanceContract::RetireNetworkMonitor".to_string(),
vec![],
)
.await
}
async fn remove_node_measurements(
&self,
epoch_id: EpochId,
node_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::RemoveNodeMeasurements { epoch_id, node_id },
"PerformanceContract::RemoveNodeMeasurements".to_string(),
vec![],
)
.await
}
async fn partial_remove_epoch_measurements(
&self,
epoch_id: EpochId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_performance_contract(
fee,
PerformanceExecuteMsg::RemoveEpochMeasurements { epoch_id },
"PerformanceContract::RemoveEpochMeasurements".to_string(),
vec![],
)
.await
}
async fn remove_epoch_measurements(
&self,
epoch_id: EpochId,
fee: Option<Fee>,
) -> Result<(), NyxdError> {
loop {
let execute_res = self
.partial_remove_epoch_measurements(epoch_id, fee.clone())
.await?;
let response = execute_res
.parse_singleton_json_contract_response::<RemoveEpochMeasurementsResponse>()?;
if !response.additional_entries_to_remove_remaining {
break;
}
}
Ok(())
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> PerformanceSigningClient for C
where
C: SigningCosmWasmClient + NymContractsProvider + Sync,
NyxdError: From<<Self as OfflineSigner>::Error>,
{
async fn execute_performance_contract(
&self,
fee: Option<Fee>,
msg: PerformanceExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError> {
let performance_contract_address = &self
.performance_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("performance contract"))?;
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
let signer_address = &self.signer_addresses()?[0];
self.execute(
signer_address,
performance_contract_address,
&msg,
fee,
memo,
funds,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
use nym_performance_contract_common::ExecuteMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_execute_variants_are_covered<C: PerformanceSigningClient + Send + Sync>(
client: C,
msg: PerformanceExecuteMsg,
) {
match msg {
PerformanceExecuteMsg::UpdateAdmin { admin } => {
client.update_admin(admin, None).ignore()
}
PerformanceExecuteMsg::Submit { epoch, data } => {
client.submit_performance(epoch, data, None).ignore()
}
PerformanceExecuteMsg::BatchSubmit { epoch, data } => {
client.batch_submit_performance(epoch, data, None).ignore()
}
PerformanceExecuteMsg::AuthoriseNetworkMonitor { address } => {
client.authorise_network_monitor(address, None).ignore()
}
PerformanceExecuteMsg::RetireNetworkMonitor { address } => {
client.retire_network_monitor(address, None).ignore()
}
ExecuteMsg::RemoveNodeMeasurements { epoch_id, node_id } => client
.remove_node_measurements(epoch_id, node_id, None)
.ignore(),
ExecuteMsg::RemoveEpochMeasurements { epoch_id } => client
.partial_remove_epoch_measurements(epoch_id, None)
.ignore(),
};
}
}
@@ -12,8 +12,6 @@ use tendermint_rpc::endpoint::broadcast;
use tracing::error;
pub use cosmrs::abci::MsgResponse;
use cosmwasm_std::from_json;
use serde::de::DeserializeOwned;
pub fn parse_singleton_u32_from_contract_response(b: Vec<u8>) -> Result<u32, NyxdError> {
if b.len() != 4 {
@@ -75,11 +73,6 @@ pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
// requires there's a single response message
pub trait ContractResponseData: Sized {
fn parse_singleton_json_contract_response<T: DeserializeOwned>(&self) -> Result<T, NyxdError> {
let b = self.to_singleton_contract_data()?;
from_json(&b).map_err(|err| err.into())
}
fn parse_singleton_u32_contract_data(&self) -> Result<u32, NyxdError> {
let b = self.to_singleton_contract_data()?;
parse_singleton_u32_from_contract_response(b)
@@ -138,14 +138,6 @@ impl NyxdClient<HttpClient> {
config,
})
}
pub fn connect_to_default_env<U>(endpoint: U) -> Result<QueryHttpRpcNyxdClient, NyxdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let config = Config::try_from_nym_network_details(&NymNetworkDetails::new_from_env())?;
Self::connect(config, endpoint)
}
}
impl NyxdClient<ReqwestRpcClient> {
@@ -276,10 +268,6 @@ impl<C, S> NymContractsProvider for NyxdClient<C, S> {
self.config.contracts.vesting_contract_address.as_ref()
}
fn performance_contract_address(&self) -> Option<&AccountId> {
self.config.contracts.performance_contract_address.as_ref()
}
fn ecash_contract_address(&self) -> Option<&AccountId> {
self.config.contracts.ecash_contract_address.as_ref()
}
+2 -2
View File
@@ -49,14 +49,14 @@ pub fn show_error<E>(e: E)
where
E: Display,
{
error!("{e}");
error!("{}", e);
}
pub fn show_error_passthrough<E>(e: E) -> E
where
E: Error + Display,
{
error!("{e}");
error!("{}", e);
e
}
@@ -42,7 +42,7 @@ pub async fn query_balance(
.address
.unwrap_or_else(|| address_from_mnemonic.expect("please provide a mnemonic"));
info!("Getting balance for {address}...");
info!("Getting balance for {}...", address);
match client.get_all_balances(&address).await {
Ok(coins) => {
@@ -57,17 +57,17 @@ pub fn get_pubkey_from_mnemonic(address: AccountId, prefix: &str, mnemonic: bip3
println!("{}", account.public_key().to_string());
}
None => {
error!("Could not derive key that matches {address}")
error!("Could not derive key that matches {}", address)
}
},
Err(e) => {
error!("Failed to derive accounts. {e}");
error!("Failed to derive accounts. {}", e);
}
}
}
pub async fn get_pubkey_from_chain(address: AccountId, client: &QueryClient) {
info!("Getting public key for address {address} from chain...");
info!("Getting public key for address {} from chain...", address);
match client.get_account(&address).await {
Ok(Some(account)) => {
if let Ok(base_account) = account.try_get_base_account() {
@@ -60,7 +60,7 @@ pub async fn send(args: Args, client: &SigningClient) {
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.hash
);
println!("Mintscan: https://ping.pub/nyx/tx/{}", &res.hash);
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
println!("Transaction result code: {}", &res.tx_result.code.value());
println!("Transaction hash: {}", &res.hash);
}
@@ -37,7 +37,7 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
let rows = InputFileReader::new(&args.input);
if let Err(e) = rows {
error!("Failed to read input file: {e}");
error!("Failed to read input file: {}", e);
return;
}
let rows = rows.unwrap();
@@ -67,7 +67,7 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
.prompt();
if let Err(e) = ans {
info!("Aborting, {e}...");
info!("Aborting, {}...", e);
return;
}
if let Ok(false) = ans {
@@ -95,15 +95,18 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.hash
);
println!("Mintscan: https://ping.pub/nyx/tx/{}", &res.hash);
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
println!("Transaction result code: {}", &res.tx_result.code.value());
println!("Transaction hash: {}", &res.hash);
if let Some(output_filename) = args.output {
println!("\nWriting output log to {output_filename}");
println!("\nWriting output log to {}", output_filename);
if let Err(e) = write_output_file(rows, res, &output_filename) {
error!("Failed to write output file {output_filename} with error {e}");
error!(
"Failed to write output file {} with error {}",
output_filename, e
);
}
}
}
@@ -133,7 +136,7 @@ fn write_output_file(
.collect::<Vec<String>>()
.join("\n");
Ok(file.write_all(format!("{data}\n").as_bytes())?)
Ok(file.write_all(format!("{}\n", data).as_bytes())?)
}
#[derive(Debug)]
@@ -168,7 +171,7 @@ impl InputFileReader {
// multiply when a whole token amount, e.g. 50nym (50.123456nym is not allowed, that must be input as 50123456unym)
let (amount, denom) = if !denom.starts_with('u') {
(amount * 1_000_000u128, format!("u{denom}"))
(amount * 1_000_000u128, format!("u{}", denom))
} else {
(amount, denom)
};
@@ -55,6 +55,6 @@ pub async fn execute(args: Args, client: SigningClient) {
.await
{
Ok(res) => info!("SUCCESS ✅\n{}", json!(res)),
Err(e) => error!("FAILURE ❌\n{e}"),
Err(e) => error!("FAILURE ❌\n{}", e),
}
}
@@ -43,7 +43,7 @@ pub struct Args {
pub async fn generate(args: Args) {
info!("Starting to generate vesting contract instantiate msg");
debug!("Received arguments: {args:?}");
debug!("Received arguments: {:?}", args);
let multisig_addr = args.multisig_addr.unwrap_or_else(|| {
let address = std::env::var(nym_network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
@@ -97,7 +97,7 @@ pub async fn generate(args: Args) {
key_size: DEFAULT_DEALINGS as u32,
};
debug!("instantiate_msg: {instantiate_msg:?}");
debug!("instantiate_msg: {:?}", instantiate_msg);
let res =
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
@@ -28,7 +28,7 @@ pub struct Args {
pub async fn generate(args: Args) {
info!("Starting to generate vesting contract instantiate msg");
debug!("Received arguments: {args:?}");
debug!("Received arguments: {:?}", args);
let group_addr = args.group_addr.unwrap_or_else(|| {
let address = std::env::var(nym_network_defaults::var_names::GROUP_CONTRACT_ADDRESS)
@@ -51,7 +51,7 @@ pub async fn generate(args: Args) {
deposit_amount: args.deposit_amount,
};
debug!("instantiate_msg: {instantiate_msg:?}");
debug!("instantiate_msg: {:?}", instantiate_msg);
let res =
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
@@ -88,7 +88,7 @@ pub struct Args {
pub async fn generate(args: Args) {
info!("Starting to generate mixnet contract instantiate msg");
debug!("Received arguments: {args:?}");
debug!("Received arguments: {:?}", args);
let initial_rewarding_params = InitialRewardingParams {
initial_reward_pool: Decimal::from_atomics(args.initial_reward_pool, 0)
@@ -114,7 +114,7 @@ pub async fn generate(args: Args) {
},
};
debug!("initial_rewarding_params: {initial_rewarding_params:?}");
debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
let rewarding_validator_address = args.rewarding_validator_address.unwrap_or_else(|| {
let address = std::env::var(nym_network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
@@ -157,10 +157,9 @@ pub async fn generate(args: Args) {
minimum: args.minimum_interval_operating_cost.amount.into(),
maximum: args.maximum_interval_operating_cost.amount.into(),
},
key_validity_in_epochs: None,
};
debug!("instantiate_msg: {instantiate_msg:?}");
debug!("instantiate_msg: {:?}", instantiate_msg);
let res =
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
@@ -31,7 +31,7 @@ pub struct Args {
pub async fn generate(args: Args) {
info!("Starting to generate vesting contract instantiate msg");
debug!("Received arguments: {args:?}");
debug!("Received arguments: {:?}", args);
let ecash_contract_address = args.ecash_contract_address.unwrap_or_else(|| {
let address = std::env::var(nym_network_defaults::var_names::ECASH_CONTRACT_ADDRESS)
@@ -60,7 +60,7 @@ pub async fn generate(args: Args) {
coconut_dkg_contract_address: coconut_dkg_contract_address.to_string(),
};
debug!("instantiate_msg: {instantiate_msg:?}");
debug!("instantiate_msg: {:?}", instantiate_msg);
let res =
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
@@ -21,7 +21,7 @@ pub struct Args {
pub async fn generate(args: Args) {
info!("Starting to generate vesting contract instantiate msg");
debug!("Received arguments: {args:?}");
debug!("Received arguments: {:?}", args);
let mixnet_contract_address = args.mixnet_contract_address.unwrap_or_else(|| {
let address = std::env::var(nym_network_defaults::var_names::MIXNET_CONTRACT_ADDRESS)
@@ -39,7 +39,7 @@ pub async fn generate(args: Args) {
mix_denom,
};
debug!("instantiate_msg: {instantiate_msg:?}");
debug!("instantiate_msg: {:?}", instantiate_msg);
let res =
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
@@ -72,7 +72,7 @@ pub async fn init(args: Args, client: SigningClient, network_details: &NymNetwor
.await
.expect("failed to instantiate the contract!");
info!("Init result: {res:?}");
info!("Init result: {:?}", res);
println!("{}", res.contract_address)
}
@@ -47,5 +47,5 @@ pub async fn migrate(args: Args, client: SigningClient) {
.expect("failed to migrate the contract!")
};
info!("Migrate result: {res:?}");
info!("Migrate result: {:?}", res);
}
@@ -31,7 +31,7 @@ pub async fn upload(args: Args, client: SigningClient) {
.await
.expect("failed to upload the contract!");
info!("Upload result: {res:?}");
info!("Upload result: {:?}", res);
println!("{}", res.code_id)
}
@@ -47,5 +47,5 @@ pub async fn delegate_to_mixnode(args: Args, client: SigningClient) {
.await
.expect("failed to delegate to mixnode!");
info!("delegating to mixnode: {res:?}");
info!("delegating to mixnode: {:?}", res);
}
@@ -196,7 +196,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
let records = match InputFileReader::new(&args.input) {
Ok(records) => records,
Err(e) => {
println!("Error reading input file: {e}");
println!("Error reading input file: {}", e);
return;
}
};
@@ -262,11 +262,11 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
}
if !undelegation_msgs.is_empty() {
println!("Undelegation records : \n{undelegation_table}\n\n");
println!("Undelegation records : \n{}\n\n", undelegation_table);
}
if !delegation_msgs.is_empty() {
println!("Delegation records : \n{delegation_table}\n\n");
println!("Delegation records : \n{}\n\n", delegation_table);
}
let ans = inquire::Confirm::new("Do you want to continue with the shown operations?")
@@ -275,7 +275,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
.prompt();
if let Err(e) = ans {
info!("Aborting, {e}...");
info!("Aborting, {}...", e);
return;
}
@@ -348,7 +348,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
if args.output.is_some() {
if let Err(e) = write_to_csv(output_details, args.output) {
info!("Failed to write to CSV, {e}");
info!("Failed to write to CSV, {}", e);
}
}
}
@@ -38,5 +38,5 @@ pub async fn migrate_vested_delegation(args: Args, client: SigningClient) {
.await
.expect("failed to migrate delegation!");
info!("migration result: {res:?}")
info!("migration result: {:?}", res)
}
@@ -40,5 +40,5 @@ pub async fn claim_delegator_reward(args: Args, client: SigningClient) {
.await
.expect("failed to claim delegator-reward");
info!("Claiming delegator reward: {res:?}")
info!("Claiming delegator reward: {:?}", res)
}
@@ -40,5 +40,5 @@ pub async fn vesting_claim_delegator_reward(args: Args, client: SigningClient) {
.await
.expect("failed to claim vesting delegator-reward");
info!("Claiming vesting delegator reward: {res:?}")
info!("Claiming vesting delegator reward: {:?}", res)
}
@@ -40,5 +40,5 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
.await
.expect("failed to remove stake from mixnode!");
info!("removing stake from mixnode: {res:?}")
info!("removing stake from mixnode: {:?}", res)
}
@@ -53,5 +53,5 @@ pub async fn vesting_delegate_to_mixnode(args: Args, client: SigningClient) {
.await
.expect("failed to delegate to mixnode!");
info!("vesting delegating to mixnode: {res:?}");
info!("vesting delegating to mixnode: {:?}", res);
}
@@ -45,5 +45,5 @@ pub async fn vesting_undelegate_from_mixnode(args: Args, client: SigningClient)
.await
.expect("failed to remove stake from vesting account on mixnode!");
info!("removing stake from vesting mixnode: {res:?}")
info!("removing stake from vesting mixnode: {:?}", res)
}
@@ -73,5 +73,5 @@ pub async fn bond_gateway(args: Args, client: SigningClient) {
.await
.expect("failed to bond gateway!");
info!("Bonding result: {res:?}")
info!("Bonding result: {:?}", res)
}
@@ -52,5 +52,5 @@ pub async fn migrate_to_nymnode(args: Args, client: SigningClient) {
.await
.expect("failed to migrate gateway!");
info!("migration result: {res:?}")
info!("migration result: {:?}", res)
}
@@ -56,5 +56,5 @@ pub async fn update_config(args: Args, client: SigningClient) {
.await
.expect("updating gateway config");
info!("gateway config updated: {res:?}")
info!("gateway config updated: {:?}", res)
}
@@ -57,5 +57,5 @@ pub async fn vesting_update_config(args: Args, client: SigningClient) {
.await
.expect("updating vesting gateway config");
info!("gateway config updated: {res:?}")
info!("gateway config updated: {:?}", res)
}
@@ -17,5 +17,5 @@ pub async fn unbond_gateway(client: SigningClient) {
.await
.expect("failed to unbond gateway!");
info!("Unbonding result: {res:?}")
info!("Unbonding result: {:?}", res)
}
@@ -73,5 +73,5 @@ pub async fn vesting_bond_gateway(args: Args, client: SigningClient) {
.await
.expect("failed to bond gateway!");
info!("Vesting bonding gateway result: {res:?}")
info!("Vesting bonding gateway result: {:?}", res)
}
@@ -17,5 +17,5 @@ pub async fn vesting_unbond_gateway(client: SigningClient) {
.await
.expect("failed to unbond vesting gateway!");
info!("Unbonding vesting result: {res:?}")
info!("Unbonding vesting result: {:?}", res)
}
@@ -106,5 +106,5 @@ pub async fn bond_mixnode(args: Args, client: SigningClient) {
.await
.expect("failed to bond mixnode!");
info!("Bonding result: {res:?}")
info!("Bonding result: {:?}", res)
}

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