Compare commits
229 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 697d55248d | |||
| 570cc36385 | |||
| ee64762b87 | |||
| f4528bb521 | |||
| f4630e0b8a | |||
| 65f948d012 | |||
| d16a288b6d | |||
| 72c40d8576 | |||
| 34e1709b75 | |||
| a06ae48e2f | |||
| 257df97e3a | |||
| 870570d5c3 | |||
| 0000baa343 | |||
| 6a307d59b4 | |||
| a4808635f9 | |||
| 29965782a2 | |||
| e5f41731ae | |||
| a6fda391ae | |||
| 1ded24dcfc | |||
| 8c42640853 | |||
| 38aabc7983 | |||
| 4324845d29 | |||
| b9524a0f58 | |||
| e7cd417894 | |||
| ca25db845a | |||
| 64a0ce31a8 | |||
| a8fe8d9bfb | |||
| c346f145d1 | |||
| 45dd6f2632 | |||
| 22d28759ab | |||
| 890d0f7440 | |||
| b342eb870e | |||
| fc71e0cafd | |||
| 1ecb57fda0 | |||
| 3c1ec82289 | |||
| 089e403d87 | |||
| dd2b477cda | |||
| 0902539332 | |||
| 0783c532de | |||
| 8817ae7805 | |||
| 6a900c3c42 | |||
| 0ba80c9a86 | |||
| d712b65ec5 | |||
| 383b2c1351 | |||
| fe7484f0f4 | |||
| f0a4350e83 | |||
| b63d04b10c | |||
| 5a35068c87 | |||
| 4899773e61 | |||
| 996f4afaf7 | |||
| d5c2a01a34 | |||
| b1c58b36fe | |||
| dfbcc781db | |||
| 5026960169 | |||
| 7c2710b61a | |||
| 0af807ac92 | |||
| bf9fc2d537 | |||
| 4182af9199 | |||
| 408d803344 | |||
| c2a5d6c035 | |||
| 1136901daf | |||
| 593a1da0ff | |||
| 9c17b7c269 | |||
| df398dbe05 | |||
| effd03b2f5 | |||
| e00db6adb9 | |||
| fd207d4699 | |||
| b9126dfc0e | |||
| 7bbe153b8f | |||
| 36e1e73ed2 | |||
| 6e23322ac4 | |||
| 729eedc960 | |||
| 025cbf5231 | |||
| 3db3959a74 | |||
| 3ba83795d4 | |||
| 39b01d10bd | |||
| f99bedd7e8 | |||
| 7717bf5cf9 | |||
| 6060ce5fb8 | |||
| 8fbad9cad8 | |||
| 650865e59a | |||
| 08e580ec8b | |||
| ad86ec9315 | |||
| 53ab4c8ec9 | |||
| f827eb4242 | |||
| 6f4b00b5c2 | |||
| d681ad20cf | |||
| 5818d58caf | |||
| da4eab8fdb | |||
| 9323ca9339 | |||
| f34c9d5d28 | |||
| b93afe7756 | |||
| 140cd7d940 | |||
| 7d233a4a2f | |||
| 5f60344c2b | |||
| c53b46ee1d | |||
| 7fc9eca46f | |||
| 4e5c765a0d | |||
| e1abbc0b5b | |||
| ce067db401 | |||
| 373cc54f3f | |||
| a276608fd0 | |||
| b332a6b556 | |||
| c610389198 | |||
| d283ecae22 | |||
| 2120acfdad | |||
| b613775551 | |||
| 73d4896b0b | |||
| b8b66fa4ad | |||
| ba59022160 | |||
| 8e2c64a867 | |||
| 73ae09cb76 | |||
| fd238b1d1b | |||
| 1f2d888626 | |||
| 9f47b05ed6 | |||
| f559a03732 | |||
| 3e12766afd | |||
| 1c93cc8a68 | |||
| 4865f7f205 | |||
| a785950d76 | |||
| 328d1c25b7 | |||
| 862a248902 | |||
| f826904407 | |||
| 67467ca76d | |||
| a53ae5b6b5 | |||
| bfc495ef29 | |||
| 9d74c22f9b | |||
| f978552a3a | |||
| b2477dd81b | |||
| dcd712430e | |||
| 5dcad5ffd4 | |||
| 210269cb9c | |||
| 8c59106add | |||
| 264771f8cf | |||
| 28d27eb84e | |||
| d57757584c | |||
| 6da00513a7 | |||
| 035faf70e4 | |||
| b238d108e6 | |||
| 5581b15094 | |||
| af19c4ecfd | |||
| 1855423981 | |||
| 229561bab9 | |||
| 7d2044c177 | |||
| 7885d3c986 | |||
| 78fb3c2293 | |||
| 0ed43d2439 | |||
| 69c1a32392 | |||
| 30ffea19a1 | |||
| 9e3bd8588d | |||
| ac7b821782 | |||
| bb372fb35c | |||
| 5f4220867a | |||
| bfa029f284 | |||
| 4c5351ba60 | |||
| 3a6058be60 | |||
| 7fcc8cdd19 | |||
| 098bd4eb3c | |||
| fa1e9988b3 | |||
| 999b4f743e | |||
| cc55abf7fb | |||
| 020edb8f84 | |||
| ae2079272b | |||
| a656429376 | |||
| 2086946e16 | |||
| 08e0892327 | |||
| d28783cb2a | |||
| 1815a2d3a5 | |||
| 1429f63d9d | |||
| 1ed087e801 | |||
| 7fce0a9692 | |||
| bef0a537b2 | |||
| fb2b2c963b | |||
| 2aa5e25532 | |||
| 588ed7dead | |||
| 519d419bbf | |||
| f5e72cefcc | |||
| 1223f50fe8 | |||
| 635ae1118a | |||
| 68e0dd1f29 | |||
| cf201cba53 | |||
| efe952fdf2 | |||
| 6d2e761319 | |||
| e699f1ad79 | |||
| 01e4abc95f | |||
| 2195310d06 | |||
| b6cd9b2bae | |||
| 682db85268 | |||
| 1ebb0c7daa | |||
| 70b15c9226 | |||
| f7e6677878 | |||
| 73e87b2deb | |||
| 6735c1ae58 | |||
| b037c8fbeb | |||
| 3fcfbad4c0 | |||
| 43e4cabb85 | |||
| 496a1bc97d | |||
| 7db4ddff56 | |||
| 6b25f83ee3 | |||
| 7602f4b130 | |||
| f762062f9f | |||
| 28a0c3eb17 | |||
| a3d7b541e2 | |||
| 7861a0081a | |||
| c8b911d5d0 | |||
| 22979ce245 | |||
| b5a3a720a4 | |||
| 0ec5fb37c2 | |||
| 2817c68e2e | |||
| c3050e5d02 | |||
| 8f1901b6e0 | |||
| 96a42fa03d | |||
| 718de1f102 | |||
| cb9d730c16 | |||
| 0e17fe5581 | |||
| b25747dd60 | |||
| b16349f2e9 | |||
| f4b5693bcb | |||
| 42a53a1c49 | |||
| 081fec72e5 | |||
| f2223dddca | |||
| 9be7b8ab56 | |||
| 40dc0d2cc7 | |||
| 19de5cb792 | |||
| 377e06daab | |||
| b54d82a01a | |||
| ad052ef498 | |||
| a3bc4af8fe | |||
| b6d57e2862 |
@@ -9,7 +9,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
@@ -30,9 +30,24 @@ jobs:
|
||||
- name: Remove existing Nym config directory (`~/.nym/`)
|
||||
run: cd documentation && ./remove_existing_config.sh
|
||||
continue-on-error: false
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
# This is the original flow
|
||||
# - name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
# run: cd documentation && ./build_all_to_dist.sh
|
||||
|
||||
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
|
||||
- name: Save current branch to ~/current_branch
|
||||
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
|
||||
- name: Git pull & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
run: git pull && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
run: cd documentation && ./build_all_to_dist.sh
|
||||
continue-on-error: false
|
||||
|
||||
- name: Switch to current branch
|
||||
run: git checkout $echo "$(cat ~/current_branch)"
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
|
||||
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
|
||||
|
||||
# End of replacemet
|
||||
|
||||
- name: Post process
|
||||
run: cd documentation && ./post_process.sh
|
||||
|
||||
@@ -112,6 +112,7 @@ jobs:
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
retention-days: 30
|
||||
|
||||
# If this was a pull_request or nightly, upload to build server
|
||||
@@ -130,6 +131,7 @@ jobs:
|
||||
cp target/release/nym-network-requester $OUTPUT_DIR
|
||||
cp target/release/nym-network-statistics $OUTPUT_DIR
|
||||
cp target/release/nymvisor $OUTPUT_DIR
|
||||
cp target/release/nym-node $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
cp target/release/explorer-api $OUTPUT_DIR
|
||||
if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
@@ -34,9 +34,25 @@ jobs:
|
||||
- name: Remove existing Nym config directory (`~/.nym/`)
|
||||
run: cd documentation && ./remove_existing_config.sh
|
||||
continue-on-error: false
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
|
||||
# This is the original flow
|
||||
# - name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
# run: cd documentation && ./build_all_to_dist.sh
|
||||
|
||||
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
|
||||
- name: Save current branch to ~/current_branch
|
||||
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
|
||||
- name: Git pull & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
run: git pull && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
run: cd documentation && ./build_all_to_dist.sh
|
||||
continue-on-error: false
|
||||
|
||||
- name: Switch to current branch
|
||||
run: git checkout $echo "$(cat ~/current_branch)"
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
|
||||
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
|
||||
|
||||
# End of replacemet
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
|
||||
@@ -30,6 +30,7 @@ jobs:
|
||||
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
|
||||
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
|
||||
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
|
||||
nymnode_hash: ${{ steps.binary-hashes.outputs.nymnode_hash }}
|
||||
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
|
||||
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
|
||||
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
|
||||
@@ -38,6 +39,7 @@ jobs:
|
||||
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
|
||||
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
|
||||
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
|
||||
nymnode_version: ${{ steps.binary-versions.outputs.nymnode_version }}
|
||||
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
|
||||
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||
@@ -81,6 +83,7 @@ jobs:
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
retention-days: 30
|
||||
|
||||
- id: create-release
|
||||
@@ -99,6 +102,7 @@ jobs:
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
|
||||
push-release-data-client:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
|
||||
@@ -102,6 +102,18 @@ jobs:
|
||||
nym-wallet/target/release/bundle/dmg/*.dmg
|
||||
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
|
||||
@@ -77,6 +77,18 @@ jobs:
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
|
||||
@@ -97,6 +97,18 @@ jobs:
|
||||
nym-wallet/target/release/bundle/msi/*.msi
|
||||
nym-wallet/target/release/bundle/msi/*.msi.zip*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
|
||||
@@ -4,6 +4,30 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.4-nutella] (2024-05-08)
|
||||
|
||||
- [fix] apply disable_poisson_rate from internal NR/IPR cfgs ([#4579])
|
||||
- updating sign commands to include nym-node ([#4578])
|
||||
- changed nym-node redirects from 308 'Permanent Redirect' to 303: 'See Other' ([#4572])
|
||||
|
||||
[#4579]: https://github.com/nymtech/nym/pull/4579
|
||||
[#4578]: https://github.com/nymtech/nym/pull/4578
|
||||
[#4572]: https://github.com/nymtech/nym/pull/4572
|
||||
|
||||
## [2024.3-eclipse] (2024-04-22)
|
||||
|
||||
- Initial release of the first iteration of the Nym Node
|
||||
- Improvements to gateway functionality
|
||||
- IPR development
|
||||
- Removal of allow list in favour of implementing an exit policy
|
||||
- Explorer delegation: enables direct delegation to nodes via the Nym Explorer
|
||||
|
||||
|
||||
## [2024.2-fast-and-furious] (2024-03-25)
|
||||
|
||||
- Internal testing pre-release
|
||||
|
||||
|
||||
## [2024.1-marabou] (2024-02-15)
|
||||
|
||||
**New Features:**
|
||||
|
||||
Generated
+1507
-3090
File diff suppressed because it is too large
Load Diff
+13
-6
@@ -24,6 +24,7 @@ members = [
|
||||
"common/bandwidth-controller",
|
||||
"common/bin-common",
|
||||
"common/client-core",
|
||||
"common/client-core/config-types",
|
||||
"common/client-core/surb-storage",
|
||||
"common/client-core/gateways-storage",
|
||||
"common/client-libs/gateway-client",
|
||||
@@ -41,6 +42,7 @@ members = [
|
||||
"common/cosmwasm-smart-contracts/name-service",
|
||||
"common/cosmwasm-smart-contracts/service-provider-directory",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
"common/country-group",
|
||||
"common/credential-storage",
|
||||
"common/credentials",
|
||||
"common/credential-utils",
|
||||
@@ -50,6 +52,7 @@ members = [
|
||||
"common/execute",
|
||||
"common/exit-policy",
|
||||
"common/http-api-client",
|
||||
"common/http-api-common",
|
||||
"common/inclusion-probability",
|
||||
"common/ip-packet-requests",
|
||||
"common/ledger",
|
||||
@@ -104,6 +107,7 @@ members = [
|
||||
"nym-browser-extension/storage",
|
||||
"nym-api/nym-api-requests",
|
||||
"nym-node",
|
||||
"nym-node/nym-node-http-api",
|
||||
"nym-node/nym-node-requests",
|
||||
"nym-outfox",
|
||||
"nym-validator-rewarder",
|
||||
@@ -118,7 +122,6 @@ members = [
|
||||
# "wasm/full-nym-wasm",
|
||||
"wasm/mix-fetch",
|
||||
"wasm/node-tester",
|
||||
"common/nym-metrics",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
@@ -132,6 +135,7 @@ default-members = [
|
||||
"tools/nymvisor",
|
||||
"explorer-api",
|
||||
"nym-validator-rewarder",
|
||||
"nym-node"
|
||||
]
|
||||
|
||||
exclude = [
|
||||
@@ -156,7 +160,8 @@ license = "Apache-2.0"
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.71"
|
||||
async-trait = "0.1.68"
|
||||
axum = "0.6.20"
|
||||
axum = "0.7.5"
|
||||
axum-extra = "0.9.3"
|
||||
base64 = "0.21.4"
|
||||
bs58 = "0.5.0"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
@@ -167,14 +172,16 @@ dotenvy = "0.15.6"
|
||||
futures = "0.3.28"
|
||||
generic-array = "0.14.7"
|
||||
getrandom = "0.2.10"
|
||||
hyper = "0.14.27"
|
||||
headers = "0.4.0"
|
||||
humantime-serde = "1.1.1"
|
||||
hyper = "1.3.1"
|
||||
k256 = "0.13"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
parking_lot = "0.12.1"
|
||||
rand = "0.8.5"
|
||||
reqwest = { version = "0.11.22", default-features = false }
|
||||
reqwest = { version = "0.12.4", default-features = false }
|
||||
schemars = "0.8.1"
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.91"
|
||||
@@ -188,8 +195,8 @@ tokio-tungstenite = { version = "0.20.1" }
|
||||
tracing = "0.1.37"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
ts-rs = "7.0.0"
|
||||
utoipa = "3.5.0"
|
||||
utoipa-swagger-ui = "3.1.5"
|
||||
utoipa = "4.2.0"
|
||||
utoipa-swagger-ui = "6.0.0"
|
||||
url = "2.4"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.33"
|
||||
version = "1.1.34"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
+291
-91
@@ -674,13 +674,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
@@ -688,7 +688,7 @@
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
@@ -793,13 +793,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"set-function-length": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -1030,18 +1036,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
@@ -1137,6 +1143,23 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-lazy-prop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||
@@ -1358,6 +1381,27 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
|
||||
@@ -1463,17 +1507,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"body-parser": "1.20.2",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -1731,20 +1775,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-symbols": "^1.0.1"
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-symbols": "^1.0.3",
|
||||
"hasown": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -1824,6 +1876,18 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.9",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
|
||||
@@ -1855,10 +1919,22 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-proto": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
|
||||
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -1867,6 +1943,30 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
@@ -2650,9 +2750,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
|
||||
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -3038,9 +3138,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
@@ -3413,6 +3513,23 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@@ -3453,14 +3570,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -5030,13 +5151,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
@@ -5044,7 +5165,7 @@
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
@@ -5122,13 +5243,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"set-function-length": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"camel-case": {
|
||||
@@ -5294,15 +5418,15 @@
|
||||
}
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"dev": true
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"dev": true
|
||||
},
|
||||
"cookie-signature": {
|
||||
@@ -5377,6 +5501,17 @@
|
||||
"execa": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"define-lazy-prop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||
@@ -5546,6 +5681,21 @@
|
||||
"integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
|
||||
"dev": true
|
||||
},
|
||||
"es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true
|
||||
},
|
||||
"es-module-lexer": {
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
|
||||
@@ -5626,17 +5776,17 @@
|
||||
}
|
||||
},
|
||||
"express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"body-parser": "1.20.2",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -5837,20 +5987,22 @@
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-symbols": "^1.0.1"
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-symbols": "^1.0.3",
|
||||
"hasown": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
@@ -5908,6 +6060,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"get-intrinsic": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.9",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
|
||||
@@ -5933,12 +6094,36 @@
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"has-symbols": {
|
||||
"has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-define-property": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"has-proto": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
|
||||
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"dev": true
|
||||
},
|
||||
"hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
@@ -6515,9 +6700,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
|
||||
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
||||
"dev": true
|
||||
},
|
||||
"object-is": {
|
||||
@@ -6803,9 +6988,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
@@ -7090,6 +7275,20 @@
|
||||
"send": "0.18.0"
|
||||
}
|
||||
},
|
||||
"set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@@ -7121,14 +7320,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
}
|
||||
},
|
||||
"signal-exit": {
|
||||
|
||||
@@ -8,5 +8,7 @@ use nym_client_core::cli_helpers::client_import_credential::{
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> {
|
||||
import_credential::<CliNativeClient, _>(args).await
|
||||
import_credential::<CliNativeClient, _>(args).await?;
|
||||
println!("successfully imported credential!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ pub enum ClientError {
|
||||
#[error("Attempted to start the client in invalid socket mode")]
|
||||
InvalidSocketMode,
|
||||
|
||||
#[error(transparent)]
|
||||
ConfigUpgradeFailure(#[from] nym_client_core::config::ConfigUpgradeFailure),
|
||||
|
||||
#[error(transparent)]
|
||||
NymIdError(#[from] NymIdError),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.33"
|
||||
version = "1.1.34"
|
||||
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"
|
||||
|
||||
@@ -10,5 +10,7 @@ use nym_client_core::cli_helpers::client_import_credential::{
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportCredentialArgs,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
import_credential::<CliSocks5Client, _>(args).await
|
||||
import_credential::<CliSocks5Client, _>(args).await?;
|
||||
println!("successfully imported credential!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ pub enum Socks5ClientError {
|
||||
#[error(transparent)]
|
||||
ClientCoreError(#[from] ClientCoreError),
|
||||
|
||||
#[error(transparent)]
|
||||
ConfigUpgradeFailure(#[from] nym_client_core::config::ConfigUpgradeFailure),
|
||||
|
||||
#[error(transparent)]
|
||||
NymIdError(#[from] NymIdError),
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ pub mod acquire;
|
||||
pub mod error;
|
||||
mod utils;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BandwidthController<C, St> {
|
||||
storage: St,
|
||||
client: C,
|
||||
|
||||
@@ -8,7 +8,6 @@ license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2"
|
||||
const-str = "0.5.6"
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
clap_complete = "4.0"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::IsTerminal;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use opentelemetry;
|
||||
@@ -14,7 +15,7 @@ pub use tracing_subscriber;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_tree;
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LoggingSettings {
|
||||
// well, we need to implement something here at some point...
|
||||
@@ -120,7 +121,7 @@ pub fn banner(crate_name: &str, crate_version: &str) -> String {
|
||||
}
|
||||
|
||||
pub fn maybe_print_banner(crate_name: &str, crate_version: &str) {
|
||||
if atty::is(atty::Stream::Stdout) {
|
||||
if std::io::stdout().is_terminal() {
|
||||
println!("{}", banner(crate_name, crate_version))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "nym-client-core"
|
||||
version = "1.1.15"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
rust-version = "1.70"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -15,7 +15,7 @@ bs58 = { workspace = true }
|
||||
cfg-if = "1.0.0"
|
||||
clap = { workspace = true, optional = true }
|
||||
futures = { workspace = true }
|
||||
humantime-serde = "1.0"
|
||||
humantime-serde = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
@@ -25,7 +25,6 @@ si-scale = "0.2.2"
|
||||
tap = "1.0.1"
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
tungstenite = { workspace = true, default-features = false }
|
||||
tokio = { workspace = true, features = ["macros"] }
|
||||
time = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
@@ -34,6 +33,7 @@ zeroize = { workspace = true }
|
||||
nym-id = { path = "../nym-id" }
|
||||
nym-bandwidth-controller = { path = "../bandwidth-controller" }
|
||||
nym-config = { path = "../config" }
|
||||
nym-country-group = { path = "../country-group" }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
|
||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||
@@ -47,6 +47,7 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu
|
||||
nym-task = { path = "../task" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"] }
|
||||
nym-client-core-surb-storage = { path = "./surb-storage" }
|
||||
nym-client-core-gateways-storage = { path = "./gateways-storage" }
|
||||
|
||||
@@ -72,8 +73,17 @@ workspace = true
|
||||
features = ["time"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||
version = "0.20.1"
|
||||
features = ["rustls-tls-native-roots"]
|
||||
workspace = true
|
||||
features = ["rustls-tls-webpki-roots"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tungstenite]
|
||||
workspace = true
|
||||
default-features = true
|
||||
features = ["rustls-tls-webpki-roots"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.tungstenite]
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen-futures]
|
||||
workspace = true
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "nym-client-core-config-types"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
humantime-serde = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror.workspace = true
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
|
||||
nym-config = { path = "../../config" }
|
||||
|
||||
nym-country-group = { path = "../../country-group" }
|
||||
nym-pemstore = { path = "../../pemstore", optional = true }
|
||||
|
||||
# those are pulling so many deps T.T
|
||||
nym-sphinx-params = { path = "../../nymsphinx/params" }
|
||||
nym-sphinx-addressing = { path = "../../nymsphinx/addressing" }
|
||||
|
||||
|
||||
[features]
|
||||
disk-persistence = ["nym-pemstore"]
|
||||
+39
-1
@@ -1,15 +1,53 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod old;
|
||||
|
||||
// preserve old structure for easier migration
|
||||
pub use old::{old_v1_1_20_2, old_v1_1_33};
|
||||
|
||||
pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite";
|
||||
pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db";
|
||||
pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.sqlite";
|
||||
|
||||
pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem";
|
||||
pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem";
|
||||
pub const DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME: &str = "private_encryption.pem";
|
||||
pub const DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME: &str = "public_encryption.pem";
|
||||
pub const DEFAULT_ACK_KEY_FILENAME: &str = "ack_key.pem";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPaths {
|
||||
pub keys: ClientKeysPaths,
|
||||
|
||||
/// Path to the file containing information about gateways used by this client,
|
||||
/// i.e. details such as their public keys, owner addresses or the network information.
|
||||
pub gateway_registrations: PathBuf,
|
||||
|
||||
/// Path to the database containing bandwidth credentials of this client.
|
||||
pub credentials_database: PathBuf,
|
||||
|
||||
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPaths {
|
||||
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
let base_dir = base_data_directory.as_ref();
|
||||
|
||||
CommonClientPaths {
|
||||
credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME),
|
||||
reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME),
|
||||
gateway_registrations: base_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME),
|
||||
keys: ClientKeysPaths::new_base(base_data_directory),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientKeysPaths {
|
||||
/// Path to file containing private identity key.
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod v1;
|
||||
pub mod v2;
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub use v1 as old_v1_1_20_2;
|
||||
pub use v2 as old_v1_1_33;
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::disk_persistence::old::v2::{
|
||||
ClientKeysPathsV2, CommonClientPathsV2, DEFAULT_GATEWAY_DETAILS_FILENAME,
|
||||
};
|
||||
use crate::error::ConfigUpgradeFailure;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type CommonClientPathsV1_1_20_2 = CommonClientPathsV1;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPathsV1 {
|
||||
pub keys: ClientKeysPathsV2,
|
||||
pub credentials_database: PathBuf,
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPathsV1 {
|
||||
pub fn upgrade_default(self) -> Result<CommonClientPathsV2, ConfigUpgradeFailure> {
|
||||
let data_dir = self
|
||||
.reply_surb_database
|
||||
.parent()
|
||||
.ok_or_else(|| ConfigUpgradeFailure {
|
||||
current_version: "1.1.20-2".to_string(),
|
||||
})?;
|
||||
Ok(CommonClientPathsV2 {
|
||||
keys: self.keys,
|
||||
gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
|
||||
credentials_database: self.credentials_database,
|
||||
reply_surb_database: self.reply_surb_database,
|
||||
})
|
||||
}
|
||||
}
|
||||
+18
-13
@@ -1,16 +1,20 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME};
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::disk_persistence::ClientKeysPaths;
|
||||
use crate::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME};
|
||||
use crate::error::ConfigUpgradeFailure;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json";
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type CommonClientPathsV1_1_33 = CommonClientPathsV2;
|
||||
pub type ClientKeysPathsV1_1_33 = ClientKeysPathsV2;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientKeysPathsV1_1_33 {
|
||||
pub struct ClientKeysPathsV2 {
|
||||
/// Path to file containing private identity key.
|
||||
pub private_identity_key_file: PathBuf,
|
||||
|
||||
@@ -32,7 +36,7 @@ pub struct ClientKeysPathsV1_1_33 {
|
||||
pub ack_key_file: PathBuf,
|
||||
}
|
||||
|
||||
impl ClientKeysPathsV1_1_33 {
|
||||
impl ClientKeysPathsV2 {
|
||||
pub fn upgrade(self) -> ClientKeysPaths {
|
||||
ClientKeysPaths {
|
||||
private_identity_key_file: self.private_identity_key_file,
|
||||
@@ -46,8 +50,8 @@ impl ClientKeysPathsV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPathsV1_1_33 {
|
||||
pub keys: ClientKeysPathsV1_1_33,
|
||||
pub struct CommonClientPathsV2 {
|
||||
pub keys: ClientKeysPathsV2,
|
||||
|
||||
/// Path to the file containing information about gateway used by this client,
|
||||
/// i.e. details such as its public key, owner address or the network information.
|
||||
@@ -60,15 +64,16 @@ pub struct CommonClientPathsV1_1_33 {
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPathsV1_1_33 {
|
||||
impl CommonClientPathsV2 {
|
||||
// note that during the upgrade process, the caller will need to extract the key and gateway details
|
||||
// manually and resave them in the new database
|
||||
pub fn upgrade_default(self) -> Result<CommonClientPaths, ClientCoreError> {
|
||||
let data_dir = self.gateway_details.parent().ok_or_else(|| {
|
||||
ClientCoreError::ConfigFileUpgradeFailure {
|
||||
pub fn upgrade_default(self) -> Result<CommonClientPaths, ConfigUpgradeFailure> {
|
||||
let data_dir = self
|
||||
.gateway_details
|
||||
.parent()
|
||||
.ok_or_else(|| ConfigUpgradeFailure {
|
||||
current_version: "1.1.33".to_string(),
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
|
||||
Ok(CommonClientPaths {
|
||||
keys: self.keys.upgrade(),
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("unable to upgrade config file from `{current_version}`")]
|
||||
pub struct ConfigUpgradeFailure {
|
||||
pub current_version: String,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum InvalidTrafficModeFailure {
|
||||
#[error("attempted to set medium toggle traffic mode with fast mode flag")]
|
||||
MediumToggleWithFastMode,
|
||||
|
||||
#[error("attempted to set medium toggle traffic mode with no cover flag")]
|
||||
MediumToggleWithNoCover,
|
||||
}
|
||||
@@ -0,0 +1,662 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(feature = "disk-persistence")]
|
||||
pub mod disk_persistence;
|
||||
pub mod error;
|
||||
pub mod old;
|
||||
|
||||
pub use error::ConfigUpgradeFailure;
|
||||
|
||||
// 'DEBUG'
|
||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||
|
||||
const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
|
||||
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
|
||||
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
|
||||
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
|
||||
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
|
||||
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
|
||||
const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead
|
||||
|
||||
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
|
||||
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
|
||||
// bandwidth bridging protocol, we can come back to a smaller timeout value
|
||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
|
||||
|
||||
// reply-surbs related:
|
||||
|
||||
// define when to request
|
||||
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs
|
||||
const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
|
||||
|
||||
// define how much to request at once
|
||||
// clients/client-core/src/client/replies/reply_controller.rs
|
||||
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
|
||||
|
||||
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
|
||||
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
// 12 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60);
|
||||
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
use crate::error::InvalidTrafficModeFailure;
|
||||
pub use nym_country_group::CountryGroup;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
pub client: Client,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S1, S2>(id: S1, version: S2) -> Self
|
||||
where
|
||||
S1: Into<String>,
|
||||
S2: Into<String>,
|
||||
{
|
||||
Config {
|
||||
client: Client::new_default(id, version),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_client_config(client: Client, debug: DebugConfig) -> Self {
|
||||
Config { client, debug }
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
self.debug.validate()
|
||||
}
|
||||
|
||||
pub fn with_debug_config(mut self, debug: DebugConfig) -> Self {
|
||||
self.debug = debug;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_disabled_credentials(mut self, disabled_credentials_mode: bool) -> Self {
|
||||
self.client.disabled_credentials_mode = disabled_credentials_mode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_nyxd(mut self, urls: Vec<Url>) -> Self {
|
||||
self.client.nyxd_urls = urls;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_custom_nyxd(&mut self, nyxd_urls: Vec<Url>) {
|
||||
self.client.nyxd_urls = nyxd_urls;
|
||||
}
|
||||
|
||||
pub fn with_custom_nym_apis(mut self, nym_api_urls: Vec<Url>) -> Self {
|
||||
self.client.nym_api_urls = nym_api_urls;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
|
||||
self.client.nym_api_urls = nym_api_urls;
|
||||
}
|
||||
|
||||
pub fn with_high_default_traffic_volume(mut self, enabled: bool) -> Self {
|
||||
if enabled {
|
||||
self.set_high_default_traffic_volume();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
|
||||
self.debug.traffic.packet_type = packet_type;
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: this should be refactored properly
|
||||
// as of 12.09.23 the below is true (not sure how this comment will rot in the future)
|
||||
// medium_toggle:
|
||||
// - sets secondary packet size to 16kb
|
||||
// - disables poisson distribution of the main traffic stream
|
||||
// - sets the cover traffic stream to 1 packet / 5s (on average)
|
||||
// - disables per hop delay
|
||||
//
|
||||
// fastmode (to be renamed to `fast-poisson`):
|
||||
// - sets average per hop delay to 10ms
|
||||
// - sets the cover traffic stream to 1 packet / 2000s (on average); for all intents and purposes it disables the stream
|
||||
// - sets the poisson distribution of the main traffic stream to 4ms, i.e. 250 packets / s on average
|
||||
//
|
||||
// no_cover:
|
||||
// - disables poisson distribution of the main traffic stream
|
||||
// - disables the secondary cover traffic stream
|
||||
#[doc(hidden)]
|
||||
pub fn try_apply_traffic_modes(
|
||||
&mut self,
|
||||
disable_poisson_process: bool,
|
||||
medium_toggle: bool,
|
||||
fast_mode: bool,
|
||||
no_cover: bool,
|
||||
) -> Result<(), InvalidTrafficModeFailure> {
|
||||
if disable_poisson_process {
|
||||
self.set_no_poisson_process()
|
||||
}
|
||||
|
||||
if medium_toggle {
|
||||
if fast_mode {
|
||||
return Err(InvalidTrafficModeFailure::MediumToggleWithFastMode);
|
||||
}
|
||||
if no_cover {
|
||||
return Err(InvalidTrafficModeFailure::MediumToggleWithNoCover);
|
||||
}
|
||||
|
||||
self.set_experimental_medium_toggle();
|
||||
}
|
||||
|
||||
if fast_mode {
|
||||
self.set_high_default_traffic_volume()
|
||||
}
|
||||
|
||||
if no_cover {
|
||||
self.set_no_cover_traffic();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
||||
// basically don't really send cover messages
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay =
|
||||
Duration::from_millis(2_000_000);
|
||||
// 250 "real" messages / s
|
||||
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
|
||||
}
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[doc(hidden)]
|
||||
pub fn set_experimental_medium_toggle(&mut self) {
|
||||
self.set_no_cover_traffic_with_keepalive();
|
||||
self.set_no_per_hop_delays();
|
||||
self.debug.traffic.secondary_packet_size = Some(PacketSize::ExtendedPacket16);
|
||||
}
|
||||
|
||||
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_poisson_process()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_poisson_process(&mut self) {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn with_disabled_cover_traffic(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_cover_traffic()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_cover_traffic(&mut self) {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn with_disabled_cover_traffic_with_keepalive(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_cover_traffic_with_keepalive()
|
||||
}
|
||||
self
|
||||
}
|
||||
pub fn set_no_cover_traffic_with_keepalive(&mut self) {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay = Duration::from_secs(5);
|
||||
}
|
||||
|
||||
pub fn with_disabled_topology_refresh(mut self, disable_topology_refresh: bool) -> Self {
|
||||
self.debug.topology.disable_refreshing = disable_topology_refresh;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
|
||||
self.set_topology_structure(topology_structure);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
|
||||
self.debug.topology.topology_structure = topology_structure;
|
||||
}
|
||||
|
||||
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
|
||||
if no_per_hop_delays {
|
||||
self.set_no_per_hop_delays()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_per_hop_delays(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::ZERO;
|
||||
self.debug.acknowledgements.average_ack_delay = Duration::ZERO;
|
||||
}
|
||||
|
||||
pub fn with_secondary_packet_size(mut self, secondary_packet_size: Option<PacketSize>) -> Self {
|
||||
self.set_secondary_packet_size(secondary_packet_size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_secondary_packet_size(&mut self, secondary_packet_size: Option<PacketSize>) {
|
||||
self.debug.traffic.secondary_packet_size = secondary_packet_size;
|
||||
}
|
||||
|
||||
pub fn set_custom_version(&mut self, version: &str) {
|
||||
self.client.version = version.to_string();
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
self.client.id.clone()
|
||||
}
|
||||
|
||||
pub fn get_disabled_credentials_mode(&self) -> bool {
|
||||
self.client.disabled_credentials_mode
|
||||
}
|
||||
|
||||
pub fn get_validator_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nyxd_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nym_api_urls.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Client {
|
||||
/// Version of the client for which this configuration was created.
|
||||
pub version: String,
|
||||
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
pub id: String,
|
||||
|
||||
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
/// to claim bandwidth without presenting bandwidth credentials.
|
||||
// TODO: this should be moved to `debug.gateway_connection`
|
||||
#[serde(default)]
|
||||
pub disabled_credentials_mode: bool,
|
||||
|
||||
/// Addresses to nyxd validators via which the client can communicate with the chain.
|
||||
#[serde(alias = "validator_urls")]
|
||||
pub nyxd_urls: Vec<Url>,
|
||||
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new_default<S1, S2>(id: S1, version: S2) -> Self
|
||||
where
|
||||
S1: Into<String>,
|
||||
S2: Into<String>,
|
||||
{
|
||||
let network = NymNetworkDetails::new_mainnet();
|
||||
let nyxd_urls = network
|
||||
.endpoints
|
||||
.iter()
|
||||
.map(|validator| validator.nyxd_url())
|
||||
.collect();
|
||||
let nym_api_urls = network
|
||||
.endpoints
|
||||
.iter()
|
||||
.filter_map(|validator| validator.api_url())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Client {
|
||||
version: version.into(),
|
||||
id: id.into(),
|
||||
disabled_credentials_mode: true,
|
||||
nyxd_urls,
|
||||
nym_api_urls,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<S: Into<String>>(
|
||||
id: S,
|
||||
version: S,
|
||||
disabled_credentials_mode: bool,
|
||||
nyxd_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
) -> Self {
|
||||
Client {
|
||||
version: version.into(),
|
||||
id: id.into(),
|
||||
disabled_credentials_mode,
|
||||
nyxd_urls,
|
||||
nym_api_urls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Traffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
|
||||
/// Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
/// poisson distribution.
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
/// Specifies the packet size used for sent messages.
|
||||
/// Do not override it unless you understand the consequences of that change.
|
||||
pub primary_packet_size: PacketSize,
|
||||
|
||||
/// Specifies the optional auxiliary packet size for optimizing message streams.
|
||||
/// Note that its use decreases overall anonymity.
|
||||
/// Do not set it it unless you understand the consequences of that change.
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
pub packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Traffic {
|
||||
pub fn validate(&self) -> bool {
|
||||
if let Some(secondary_packet_size) = self.secondary_packet_size {
|
||||
if secondary_packet_size == PacketSize::AckPacket
|
||||
|| secondary_packet_size == self.primary_packet_size
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Traffic {
|
||||
fn default() -> Self {
|
||||
Traffic {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
packet_type: PacketType::Mix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTraffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
|
||||
/// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
|
||||
/// Only applicable if `secondary_packet_size` is enabled.
|
||||
pub cover_traffic_primary_size_ratio: f64,
|
||||
|
||||
/// Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl Default for CoverTraffic {
|
||||
fn default() -> Self {
|
||||
CoverTraffic {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnection {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for GatewayConnection {
|
||||
fn default() -> Self {
|
||||
GatewayConnection {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Acknowledgements {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
|
||||
/// Value multiplied with the expected round trip time of an acknowledgement packet before
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
/// In an ideal network with 0 latency, this value would have been 1.
|
||||
pub ack_wait_multiplier: f64,
|
||||
|
||||
/// Value added to the expected round trip time of an acknowledgement packet before
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
/// In an ideal network with 0 latency, this value would have been 0.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl Default for Acknowledgements {
|
||||
fn default() -> Self {
|
||||
Acknowledgements {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Topology {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
|
||||
/// During topology refresh, test packets are sent through every single possible network
|
||||
/// path. This timeout determines waiting period until it is decided that the packet
|
||||
/// did not reach its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_resolution_timeout: Duration,
|
||||
|
||||
/// Specifies whether the client should not refresh the network topology after obtaining
|
||||
/// the first valid instance.
|
||||
/// Supersedes `topology_refresh_rate_ms`.
|
||||
pub disable_refreshing: bool,
|
||||
|
||||
/// Defines how long the client is going to wait on startup for its gateway to come online,
|
||||
/// before abandoning the procedure.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub max_startup_gateway_waiting_period: Duration,
|
||||
|
||||
/// Specifies the mixnode topology to be used for sending packets.
|
||||
pub topology_structure: TopologyStructure,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TopologyStructure {
|
||||
#[default]
|
||||
NymApi,
|
||||
GeoAware(GroupBy),
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupBy {
|
||||
CountryGroup(CountryGroup),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupBy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupBy::CountryGroup(group) => write!(f, "group: {group}"),
|
||||
GroupBy::NymAddress(address) => write!(f, "address: {address}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Topology {
|
||||
fn default() -> Self {
|
||||
Topology {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
|
||||
topology_structure: TopologyStructure::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbs {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
|
||||
/// Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
|
||||
/// Defines the minimum number of reply surbs the client would request.
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
|
||||
/// Defines the maximum number of reply surbs the client would request.
|
||||
pub maximum_reply_surb_request_size: u32,
|
||||
|
||||
/// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
|
||||
pub maximum_allowed_reply_surb_request_size: u32,
|
||||
|
||||
/// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
|
||||
/// for more even though in theory they wouldn't need to.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_rerequest_waiting_period: Duration,
|
||||
|
||||
/// Defines maximum amount of time the client is going to wait for reply surbs before
|
||||
/// deciding it's never going to get them and would drop all pending messages
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_drop_waiting_period: Duration,
|
||||
|
||||
/// Defines maximum amount of time given reply surb is going to be valid for.
|
||||
/// This is going to be superseded by key rotation once implemented.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_age: Duration,
|
||||
|
||||
/// Defines maximum amount of time given reply key is going to be valid for.
|
||||
/// This is going to be superseded by key rotation once implemented.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_key_age: Duration,
|
||||
|
||||
/// Specifies the number of mixnet hops the packet should go through. If not specified, then
|
||||
/// the default value is used.
|
||||
pub surb_mix_hops: Option<u8>,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbs {
|
||||
fn default() -> Self {
|
||||
ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_rerequest_waiting_period:
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
surb_mix_hops: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfig {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: Traffic,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTraffic,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnection,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: Acknowledgements,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: Topology,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbs,
|
||||
}
|
||||
|
||||
impl DebugConfig {
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.traffic.validate()
|
||||
}
|
||||
}
|
||||
|
||||
// it could be derived, sure, but I'd rather have an explicit implementation in case we had to change
|
||||
// something manually at some point
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for DebugConfig {
|
||||
fn default() -> Self {
|
||||
DebugConfig {
|
||||
traffic: Default::default(),
|
||||
cover_traffic: Default::default(),
|
||||
gateway_connection: Default::default(),
|
||||
acknowledgements: Default::default(),
|
||||
topology: Default::default(),
|
||||
reply_surbs: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod v1;
|
||||
pub mod v2;
|
||||
pub mod v3;
|
||||
pub mod v4;
|
||||
pub mod v5;
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub use v1 as old_config_v1_1_13;
|
||||
pub use v2 as old_config_v1_1_20;
|
||||
pub use v3 as old_config_v1_1_20_2;
|
||||
pub use v4 as old_config_v1_1_30;
|
||||
pub use v5 as old_config_v1_1_33;
|
||||
+40
-35
@@ -1,23 +1,28 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20::{
|
||||
AcknowledgementsV1_1_20, ClientV1_1_20, ConfigV1_1_20, CoverTrafficV1_1_20, DebugConfigV1_1_20,
|
||||
GatewayConnectionV1_1_20, LoggingV1_1_20, ReplySurbsV1_1_20, TopologyV1_1_20, TrafficV1_1_20,
|
||||
DEFAULT_ACK_WAIT_ADDITION, DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
DEFAULT_GATEWAY_RESPONSE_TIMEOUT, DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_AGE, DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
use crate::old::v2::{
|
||||
AcknowledgementsV2, ClientV2, ConfigV2, CoverTrafficV2, DebugConfigV2, GatewayConnectionV2,
|
||||
LoggingV2, ReplySurbsV2, TopologyV2, TrafficV2, DEFAULT_ACK_WAIT_ADDITION,
|
||||
DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY, DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
DEFAULT_MAXIMUM_REPLY_KEY_AGE, DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD, DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
DEFAULT_TOPOLOGY_REFRESH_RATE, DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
};
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx_params::PacketSize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type OldConfigV1_1_13<T> = ConfigV1<T>;
|
||||
pub type OldLoggingV1_1_13 = LoggingV1;
|
||||
pub type OldDebugConfigV1_1_13 = DebugConfigV1;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ExtendedPacketSize {
|
||||
@@ -38,28 +43,28 @@ impl From<ExtendedPacketSize> for PacketSize {
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13<T> {
|
||||
pub client: ClientV1_1_20<T>,
|
||||
pub struct ConfigV1<T> {
|
||||
pub client: ClientV2<T>,
|
||||
|
||||
#[serde(default)]
|
||||
pub logging: OldLoggingV1_1_13,
|
||||
pub logging: LoggingV1,
|
||||
#[serde(default)]
|
||||
pub debug: OldDebugConfigV1_1_13,
|
||||
pub debug: DebugConfigV1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldLoggingV1_1_13 {}
|
||||
pub struct LoggingV1 {}
|
||||
|
||||
impl From<OldLoggingV1_1_13> for LoggingV1_1_20 {
|
||||
fn from(_value: OldLoggingV1_1_13) -> Self {
|
||||
LoggingV1_1_20 {}
|
||||
impl From<LoggingV1> for LoggingV2 {
|
||||
fn from(_value: LoggingV1) -> Self {
|
||||
LoggingV2 {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct OldDebugConfigV1_1_13 {
|
||||
pub struct DebugConfigV1 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
|
||||
@@ -114,10 +119,10 @@ pub struct OldDebugConfigV1_1_13 {
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl From<OldDebugConfigV1_1_13> for DebugConfigV1_1_20 {
|
||||
fn from(value: OldDebugConfigV1_1_13) -> Self {
|
||||
DebugConfigV1_1_20 {
|
||||
traffic: TrafficV1_1_20 {
|
||||
impl From<DebugConfigV1> for DebugConfigV2 {
|
||||
fn from(value: DebugConfigV1) -> Self {
|
||||
DebugConfigV2 {
|
||||
traffic: TrafficV2 {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
@@ -125,25 +130,25 @@ impl From<OldDebugConfigV1_1_13> for DebugConfigV1_1_20 {
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: value.use_extended_packet_size.map(Into::into),
|
||||
},
|
||||
cover_traffic: CoverTrafficV1_1_20 {
|
||||
cover_traffic: CoverTrafficV2 {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
..CoverTrafficV1_1_20::default()
|
||||
..CoverTrafficV2::default()
|
||||
},
|
||||
gateway_connection: GatewayConnectionV1_1_20 {
|
||||
gateway_connection: GatewayConnectionV2 {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
},
|
||||
acknowledgements: AcknowledgementsV1_1_20 {
|
||||
acknowledgements: AcknowledgementsV2 {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
},
|
||||
topology: TopologyV1_1_20 {
|
||||
topology: TopologyV2 {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: false,
|
||||
},
|
||||
reply_surbs: ReplySurbsV1_1_20 {
|
||||
reply_surbs: ReplySurbsV2 {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
@@ -161,9 +166,9 @@ impl From<OldDebugConfigV1_1_13> for DebugConfigV1_1_20 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OldDebugConfigV1_1_13 {
|
||||
impl Default for DebugConfigV1 {
|
||||
fn default() -> Self {
|
||||
OldDebugConfigV1_1_13 {
|
||||
DebugConfigV1 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
@@ -190,10 +195,10 @@ impl Default for OldDebugConfigV1_1_13 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> From<OldConfigV1_1_13<T>> for ConfigV1_1_20<U> {
|
||||
fn from(value: OldConfigV1_1_13<T>) -> Self {
|
||||
ConfigV1_1_20 {
|
||||
client: ClientV1_1_20 {
|
||||
impl<T, U> From<ConfigV1<T>> for ConfigV2<U> {
|
||||
fn from(value: ConfigV1<T>) -> Self {
|
||||
ConfigV2 {
|
||||
client: ClientV2 {
|
||||
version: value.client.version,
|
||||
id: value.client.id,
|
||||
disabled_credentials_mode: value.client.disabled_credentials_mode,
|
||||
+76
-63
@@ -1,12 +1,11 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20_2::{
|
||||
AcknowledgementsV1_1_20_2, CoverTrafficV1_1_20_2, DebugConfigV1_1_20_2,
|
||||
GatewayConnectionV1_1_20_2, GatewayEndpointConfigV1_1_20_2, ReplySurbsV1_1_20_2,
|
||||
TopologyV1_1_20_2, TrafficV1_1_20_2,
|
||||
use crate::old::v3::{
|
||||
AcknowledgementsV3, CoverTrafficV3, DebugConfigV3, GatewayConnectionV3,
|
||||
GatewayEndpointConfigV3, ReplySurbsV3, TopologyV3, TrafficV3,
|
||||
};
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
@@ -54,27 +53,41 @@ pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(
|
||||
// 24 hours
|
||||
pub(crate) const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type ConfigV1_1_20<T> = ConfigV2<T>;
|
||||
pub type ClientV1_1_20<T> = ClientV2<T>;
|
||||
pub type LoggingV1_1_20 = LoggingV2;
|
||||
pub type DebugConfigV1_1_20 = DebugConfigV2;
|
||||
pub type GatewayEndpointConfigV1_1_20 = GatewayEndpointConfigV2;
|
||||
|
||||
pub type TrafficV1_1_20 = TrafficV2;
|
||||
pub type CoverTrafficV1_1_20 = CoverTrafficV2;
|
||||
pub type GatewayConnectionV1_1_20 = GatewayConnectionV2;
|
||||
pub type AcknowledgementsV1_1_20 = AcknowledgementsV2;
|
||||
pub type TopologyV1_1_20 = TopologyV2;
|
||||
pub type ReplySurbsV1_1_20 = ReplySurbsV2;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20<T> {
|
||||
pub client: ClientV1_1_20<T>,
|
||||
pub struct ConfigV2<T> {
|
||||
pub client: ClientV2<T>,
|
||||
|
||||
#[serde(default)]
|
||||
pub logging: LoggingV1_1_20,
|
||||
pub logging: LoggingV2,
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfigV1_1_20,
|
||||
pub debug: DebugConfigV2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct GatewayEndpointConfigV1_1_20 {
|
||||
pub struct GatewayEndpointConfigV2 {
|
||||
pub gateway_id: String,
|
||||
pub gateway_owner: String,
|
||||
pub gateway_listener: String,
|
||||
}
|
||||
|
||||
impl From<GatewayEndpointConfigV1_1_20> for GatewayEndpointConfigV1_1_20_2 {
|
||||
fn from(value: GatewayEndpointConfigV1_1_20) -> Self {
|
||||
GatewayEndpointConfigV1_1_20_2 {
|
||||
impl From<GatewayEndpointConfigV2> for GatewayEndpointConfigV3 {
|
||||
fn from(value: GatewayEndpointConfigV2) -> Self {
|
||||
GatewayEndpointConfigV3 {
|
||||
gateway_id: value.gateway_id,
|
||||
gateway_owner: value.gateway_owner,
|
||||
gateway_listener: value.gateway_listener,
|
||||
@@ -83,7 +96,7 @@ impl From<GatewayEndpointConfigV1_1_20> for GatewayEndpointConfigV1_1_20_2 {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientV1_1_20<T> {
|
||||
pub struct ClientV2<T> {
|
||||
pub version: String,
|
||||
pub id: String,
|
||||
#[serde(default)]
|
||||
@@ -98,7 +111,7 @@ pub struct ClientV1_1_20<T> {
|
||||
pub public_encryption_key_file: PathBuf,
|
||||
pub gateway_shared_key_file: PathBuf,
|
||||
pub ack_key_file: PathBuf,
|
||||
pub gateway_endpoint: GatewayEndpointConfigV1_1_20,
|
||||
pub gateway_endpoint: GatewayEndpointConfigV2,
|
||||
pub database_path: PathBuf,
|
||||
#[serde(default)]
|
||||
pub reply_surb_database_path: PathBuf,
|
||||
@@ -110,11 +123,11 @@ pub struct ClientV1_1_20<T> {
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LoggingV1_1_20 {}
|
||||
pub struct LoggingV2 {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct TrafficV1_1_20 {
|
||||
pub struct TrafficV2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -124,9 +137,9 @@ pub struct TrafficV1_1_20 {
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
}
|
||||
|
||||
impl From<TrafficV1_1_20> for TrafficV1_1_20_2 {
|
||||
fn from(value: TrafficV1_1_20) -> Self {
|
||||
TrafficV1_1_20_2 {
|
||||
impl From<TrafficV2> for TrafficV3 {
|
||||
fn from(value: TrafficV2) -> Self {
|
||||
TrafficV3 {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
@@ -138,9 +151,9 @@ impl From<TrafficV1_1_20> for TrafficV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TrafficV1_1_20 {
|
||||
impl Default for TrafficV2 {
|
||||
fn default() -> Self {
|
||||
TrafficV1_1_20 {
|
||||
TrafficV2 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
@@ -152,16 +165,16 @@ impl Default for TrafficV1_1_20 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTrafficV1_1_20 {
|
||||
pub struct CoverTrafficV2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
pub cover_traffic_primary_size_ratio: f64,
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl From<CoverTrafficV1_1_20> for CoverTrafficV1_1_20_2 {
|
||||
fn from(value: CoverTrafficV1_1_20) -> Self {
|
||||
CoverTrafficV1_1_20_2 {
|
||||
impl From<CoverTrafficV2> for CoverTrafficV3 {
|
||||
fn from(value: CoverTrafficV2) -> Self {
|
||||
CoverTrafficV3 {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
cover_traffic_primary_size_ratio: value.cover_traffic_primary_size_ratio,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
@@ -169,9 +182,9 @@ impl From<CoverTrafficV1_1_20> for CoverTrafficV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CoverTrafficV1_1_20 {
|
||||
impl Default for CoverTrafficV2 {
|
||||
fn default() -> Self {
|
||||
CoverTrafficV1_1_20 {
|
||||
CoverTrafficV2 {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
@@ -181,22 +194,22 @@ impl Default for CoverTrafficV1_1_20 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnectionV1_1_20 {
|
||||
pub struct GatewayConnectionV2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl From<GatewayConnectionV1_1_20> for GatewayConnectionV1_1_20_2 {
|
||||
fn from(value: GatewayConnectionV1_1_20) -> Self {
|
||||
GatewayConnectionV1_1_20_2 {
|
||||
impl From<GatewayConnectionV2> for GatewayConnectionV3 {
|
||||
fn from(value: GatewayConnectionV2) -> Self {
|
||||
GatewayConnectionV3 {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GatewayConnectionV1_1_20 {
|
||||
impl Default for GatewayConnectionV2 {
|
||||
fn default() -> Self {
|
||||
GatewayConnectionV1_1_20 {
|
||||
GatewayConnectionV2 {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
@@ -204,7 +217,7 @@ impl Default for GatewayConnectionV1_1_20 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct AcknowledgementsV1_1_20 {
|
||||
pub struct AcknowledgementsV2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
pub ack_wait_multiplier: f64,
|
||||
@@ -212,9 +225,9 @@ pub struct AcknowledgementsV1_1_20 {
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl From<AcknowledgementsV1_1_20> for AcknowledgementsV1_1_20_2 {
|
||||
fn from(value: AcknowledgementsV1_1_20) -> Self {
|
||||
AcknowledgementsV1_1_20_2 {
|
||||
impl From<AcknowledgementsV2> for AcknowledgementsV3 {
|
||||
fn from(value: AcknowledgementsV2) -> Self {
|
||||
AcknowledgementsV3 {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
@@ -222,9 +235,9 @@ impl From<AcknowledgementsV1_1_20> for AcknowledgementsV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AcknowledgementsV1_1_20 {
|
||||
impl Default for AcknowledgementsV2 {
|
||||
fn default() -> Self {
|
||||
AcknowledgementsV1_1_20 {
|
||||
AcknowledgementsV2 {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
@@ -234,7 +247,7 @@ impl Default for AcknowledgementsV1_1_20 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TopologyV1_1_20 {
|
||||
pub struct TopologyV2 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -242,9 +255,9 @@ pub struct TopologyV1_1_20 {
|
||||
pub disable_refreshing: bool,
|
||||
}
|
||||
|
||||
impl From<TopologyV1_1_20> for TopologyV1_1_20_2 {
|
||||
fn from(value: TopologyV1_1_20) -> Self {
|
||||
TopologyV1_1_20_2 {
|
||||
impl From<TopologyV2> for TopologyV3 {
|
||||
fn from(value: TopologyV2) -> Self {
|
||||
TopologyV3 {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: value.disable_refreshing,
|
||||
@@ -252,9 +265,9 @@ impl From<TopologyV1_1_20> for TopologyV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyV1_1_20 {
|
||||
impl Default for TopologyV2 {
|
||||
fn default() -> Self {
|
||||
TopologyV1_1_20 {
|
||||
TopologyV2 {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
@@ -264,7 +277,7 @@ impl Default for TopologyV1_1_20 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbsV1_1_20 {
|
||||
pub struct ReplySurbsV2 {
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
@@ -280,9 +293,9 @@ pub struct ReplySurbsV1_1_20 {
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl From<ReplySurbsV1_1_20> for ReplySurbsV1_1_20_2 {
|
||||
fn from(value: ReplySurbsV1_1_20) -> Self {
|
||||
ReplySurbsV1_1_20_2 {
|
||||
impl From<ReplySurbsV2> for ReplySurbsV3 {
|
||||
fn from(value: ReplySurbsV2) -> Self {
|
||||
ReplySurbsV3 {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
@@ -297,9 +310,9 @@ impl From<ReplySurbsV1_1_20> for ReplySurbsV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ReplySurbsV1_1_20 {
|
||||
impl Default for ReplySurbsV2 {
|
||||
fn default() -> Self {
|
||||
ReplySurbsV1_1_20 {
|
||||
ReplySurbsV2 {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
@@ -316,18 +329,18 @@ impl Default for ReplySurbsV1_1_20 {
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfigV1_1_20 {
|
||||
pub traffic: TrafficV1_1_20,
|
||||
pub cover_traffic: CoverTrafficV1_1_20,
|
||||
pub gateway_connection: GatewayConnectionV1_1_20,
|
||||
pub acknowledgements: AcknowledgementsV1_1_20,
|
||||
pub topology: TopologyV1_1_20,
|
||||
pub reply_surbs: ReplySurbsV1_1_20,
|
||||
pub struct DebugConfigV2 {
|
||||
pub traffic: TrafficV2,
|
||||
pub cover_traffic: CoverTrafficV2,
|
||||
pub gateway_connection: GatewayConnectionV2,
|
||||
pub acknowledgements: AcknowledgementsV2,
|
||||
pub topology: TopologyV2,
|
||||
pub reply_surbs: ReplySurbsV2,
|
||||
}
|
||||
|
||||
impl From<DebugConfigV1_1_20> for DebugConfigV1_1_20_2 {
|
||||
fn from(value: DebugConfigV1_1_20) -> Self {
|
||||
DebugConfigV1_1_20_2 {
|
||||
impl From<DebugConfigV2> for DebugConfigV3 {
|
||||
fn from(value: DebugConfigV2) -> Self {
|
||||
DebugConfigV3 {
|
||||
traffic: value.traffic.into(),
|
||||
cover_traffic: value.cover_traffic.into(),
|
||||
gateway_connection: value.gateway_connection.into(),
|
||||
+80
-67
@@ -1,12 +1,12 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_30::{
|
||||
AcknowledgementsV1_1_30, ClientV1_1_30, ConfigV1_1_30, CoverTrafficV1_1_30, DebugConfigV1_1_30,
|
||||
GatewayConnectionV1_1_30, ReplySurbsV1_1_30, TopologyV1_1_30, TrafficV1_1_30,
|
||||
use crate::old::v4::{
|
||||
AcknowledgementsV4, ClientV4, ConfigV4, CoverTrafficV4, DebugConfigV4, GatewayConnectionV4,
|
||||
ReplySurbsV4, TopologyV4, TrafficV4,
|
||||
};
|
||||
use crate::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use crate::old::v5::GatewayEndpointConfigV5;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -50,18 +50,31 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type ConfigV1_1_20_2 = ConfigV3;
|
||||
pub type ClientV1_1_20_2 = ClientV3;
|
||||
pub type DebugConfigV1_1_20_2 = DebugConfigV3;
|
||||
pub type GatewayEndpointConfigV1_1_20_2 = GatewayEndpointConfigV3;
|
||||
|
||||
pub type TrafficV1_1_20_2 = TrafficV3;
|
||||
pub type CoverTrafficV1_1_20_2 = CoverTrafficV3;
|
||||
pub type GatewayConnectionV1_1_20_2 = GatewayConnectionV3;
|
||||
pub type AcknowledgementsV1_1_20_2 = AcknowledgementsV3;
|
||||
pub type TopologyV1_1_20_2 = TopologyV3;
|
||||
pub type ReplySurbsV1_1_20_2 = ReplySurbsV3;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20_2 {
|
||||
pub client: ClientV1_1_20_2,
|
||||
pub struct ConfigV3 {
|
||||
pub client: ClientV3,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfigV1_1_20_2,
|
||||
pub debug: DebugConfigV3,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_20_2> for ConfigV1_1_30 {
|
||||
fn from(value: ConfigV1_1_20_2) -> Self {
|
||||
ConfigV1_1_30 {
|
||||
impl From<ConfigV3> for ConfigV4 {
|
||||
fn from(value: ConfigV3) -> Self {
|
||||
ConfigV4 {
|
||||
client: value.client.into(),
|
||||
debug: value.debug.into(),
|
||||
}
|
||||
@@ -69,7 +82,7 @@ impl From<ConfigV1_1_20_2> for ConfigV1_1_30 {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct GatewayEndpointConfigV1_1_20_2 {
|
||||
pub struct GatewayEndpointConfigV3 {
|
||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||
pub gateway_id: String,
|
||||
@@ -81,9 +94,9 @@ pub struct GatewayEndpointConfigV1_1_20_2 {
|
||||
pub gateway_listener: String,
|
||||
}
|
||||
|
||||
impl From<GatewayEndpointConfigV1_1_20_2> for OldGatewayEndpointConfigV1_1_33 {
|
||||
fn from(value: GatewayEndpointConfigV1_1_20_2) -> Self {
|
||||
OldGatewayEndpointConfigV1_1_33 {
|
||||
impl From<GatewayEndpointConfigV3> for GatewayEndpointConfigV5 {
|
||||
fn from(value: GatewayEndpointConfigV3) -> Self {
|
||||
GatewayEndpointConfigV5 {
|
||||
gateway_id: value.gateway_id,
|
||||
gateway_owner: value.gateway_owner,
|
||||
gateway_listener: value.gateway_listener,
|
||||
@@ -92,7 +105,7 @@ impl From<GatewayEndpointConfigV1_1_20_2> for OldGatewayEndpointConfigV1_1_33 {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct ClientV1_1_20_2 {
|
||||
pub struct ClientV3 {
|
||||
pub version: String,
|
||||
|
||||
pub id: String,
|
||||
@@ -105,12 +118,12 @@ pub struct ClientV1_1_20_2 {
|
||||
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
pub gateway_endpoint: GatewayEndpointConfigV1_1_20_2,
|
||||
pub gateway_endpoint: GatewayEndpointConfigV3,
|
||||
}
|
||||
|
||||
impl From<ClientV1_1_20_2> for ClientV1_1_30 {
|
||||
fn from(value: ClientV1_1_20_2) -> Self {
|
||||
ClientV1_1_30 {
|
||||
impl From<ClientV3> for ClientV4 {
|
||||
fn from(value: ClientV3) -> Self {
|
||||
ClientV4 {
|
||||
version: value.version,
|
||||
id: value.id,
|
||||
disabled_credentials_mode: value.disabled_credentials_mode,
|
||||
@@ -122,7 +135,7 @@ impl From<ClientV1_1_20_2> for ClientV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct TrafficV1_1_20_2 {
|
||||
pub struct TrafficV3 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -133,9 +146,9 @@ pub struct TrafficV1_1_20_2 {
|
||||
pub packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl From<TrafficV1_1_20_2> for TrafficV1_1_30 {
|
||||
fn from(value: TrafficV1_1_20_2) -> Self {
|
||||
TrafficV1_1_30 {
|
||||
impl From<TrafficV3> for TrafficV4 {
|
||||
fn from(value: TrafficV3) -> Self {
|
||||
TrafficV4 {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
@@ -147,9 +160,9 @@ impl From<TrafficV1_1_20_2> for TrafficV1_1_30 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TrafficV1_1_20_2 {
|
||||
impl Default for TrafficV3 {
|
||||
fn default() -> Self {
|
||||
TrafficV1_1_20_2 {
|
||||
TrafficV3 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
@@ -162,16 +175,16 @@ impl Default for TrafficV1_1_20_2 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTrafficV1_1_20_2 {
|
||||
pub struct CoverTrafficV3 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
pub cover_traffic_primary_size_ratio: f64,
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl From<CoverTrafficV1_1_20_2> for CoverTrafficV1_1_30 {
|
||||
fn from(value: CoverTrafficV1_1_20_2) -> Self {
|
||||
CoverTrafficV1_1_30 {
|
||||
impl From<CoverTrafficV3> for CoverTrafficV4 {
|
||||
fn from(value: CoverTrafficV3) -> Self {
|
||||
CoverTrafficV4 {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
cover_traffic_primary_size_ratio: value.cover_traffic_primary_size_ratio,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
@@ -179,9 +192,9 @@ impl From<CoverTrafficV1_1_20_2> for CoverTrafficV1_1_30 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CoverTrafficV1_1_20_2 {
|
||||
impl Default for CoverTrafficV3 {
|
||||
fn default() -> Self {
|
||||
CoverTrafficV1_1_20_2 {
|
||||
CoverTrafficV3 {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
@@ -191,22 +204,22 @@ impl Default for CoverTrafficV1_1_20_2 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnectionV1_1_20_2 {
|
||||
pub struct GatewayConnectionV3 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl From<GatewayConnectionV1_1_20_2> for GatewayConnectionV1_1_30 {
|
||||
fn from(value: GatewayConnectionV1_1_20_2) -> Self {
|
||||
GatewayConnectionV1_1_30 {
|
||||
impl From<GatewayConnectionV3> for GatewayConnectionV4 {
|
||||
fn from(value: GatewayConnectionV3) -> Self {
|
||||
GatewayConnectionV4 {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GatewayConnectionV1_1_20_2 {
|
||||
impl Default for GatewayConnectionV3 {
|
||||
fn default() -> Self {
|
||||
GatewayConnectionV1_1_20_2 {
|
||||
GatewayConnectionV3 {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
@@ -214,7 +227,7 @@ impl Default for GatewayConnectionV1_1_20_2 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct AcknowledgementsV1_1_20_2 {
|
||||
pub struct AcknowledgementsV3 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
pub ack_wait_multiplier: f64,
|
||||
@@ -222,9 +235,9 @@ pub struct AcknowledgementsV1_1_20_2 {
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl From<AcknowledgementsV1_1_20_2> for AcknowledgementsV1_1_30 {
|
||||
fn from(value: AcknowledgementsV1_1_20_2) -> Self {
|
||||
AcknowledgementsV1_1_30 {
|
||||
impl From<AcknowledgementsV3> for AcknowledgementsV4 {
|
||||
fn from(value: AcknowledgementsV3) -> Self {
|
||||
AcknowledgementsV4 {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
@@ -232,9 +245,9 @@ impl From<AcknowledgementsV1_1_20_2> for AcknowledgementsV1_1_30 {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AcknowledgementsV1_1_20_2 {
|
||||
impl Default for AcknowledgementsV3 {
|
||||
fn default() -> Self {
|
||||
AcknowledgementsV1_1_20_2 {
|
||||
AcknowledgementsV3 {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
@@ -244,7 +257,7 @@ impl Default for AcknowledgementsV1_1_20_2 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TopologyV1_1_20_2 {
|
||||
pub struct TopologyV3 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -252,9 +265,9 @@ pub struct TopologyV1_1_20_2 {
|
||||
pub disable_refreshing: bool,
|
||||
}
|
||||
|
||||
impl Default for TopologyV1_1_20_2 {
|
||||
impl Default for TopologyV3 {
|
||||
fn default() -> Self {
|
||||
TopologyV1_1_20_2 {
|
||||
TopologyV3 {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
@@ -262,9 +275,9 @@ impl Default for TopologyV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TopologyV1_1_20_2> for TopologyV1_1_30 {
|
||||
fn from(value: TopologyV1_1_20_2) -> Self {
|
||||
TopologyV1_1_30 {
|
||||
impl From<TopologyV3> for TopologyV4 {
|
||||
fn from(value: TopologyV3) -> Self {
|
||||
TopologyV4 {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
disable_refreshing: value.disable_refreshing,
|
||||
@@ -275,7 +288,7 @@ impl From<TopologyV1_1_20_2> for TopologyV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbsV1_1_20_2 {
|
||||
pub struct ReplySurbsV3 {
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
@@ -291,9 +304,9 @@ pub struct ReplySurbsV1_1_20_2 {
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbsV1_1_20_2 {
|
||||
impl Default for ReplySurbsV3 {
|
||||
fn default() -> Self {
|
||||
ReplySurbsV1_1_20_2 {
|
||||
ReplySurbsV3 {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
@@ -308,9 +321,9 @@ impl Default for ReplySurbsV1_1_20_2 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReplySurbsV1_1_20_2> for ReplySurbsV1_1_30 {
|
||||
fn from(value: ReplySurbsV1_1_20_2) -> Self {
|
||||
ReplySurbsV1_1_30 {
|
||||
impl From<ReplySurbsV3> for ReplySurbsV4 {
|
||||
fn from(value: ReplySurbsV3) -> Self {
|
||||
ReplySurbsV4 {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
@@ -327,18 +340,18 @@ impl From<ReplySurbsV1_1_20_2> for ReplySurbsV1_1_30 {
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfigV1_1_20_2 {
|
||||
pub traffic: TrafficV1_1_20_2,
|
||||
pub cover_traffic: CoverTrafficV1_1_20_2,
|
||||
pub gateway_connection: GatewayConnectionV1_1_20_2,
|
||||
pub acknowledgements: AcknowledgementsV1_1_20_2,
|
||||
pub topology: TopologyV1_1_20_2,
|
||||
pub reply_surbs: ReplySurbsV1_1_20_2,
|
||||
pub struct DebugConfigV3 {
|
||||
pub traffic: TrafficV3,
|
||||
pub cover_traffic: CoverTrafficV3,
|
||||
pub gateway_connection: GatewayConnectionV3,
|
||||
pub acknowledgements: AcknowledgementsV3,
|
||||
pub topology: TopologyV3,
|
||||
pub reply_surbs: ReplySurbsV3,
|
||||
}
|
||||
|
||||
impl From<DebugConfigV1_1_20_2> for DebugConfigV1_1_30 {
|
||||
fn from(value: DebugConfigV1_1_20_2) -> Self {
|
||||
DebugConfigV1_1_30 {
|
||||
impl From<DebugConfigV3> for DebugConfigV4 {
|
||||
fn from(value: DebugConfigV3) -> Self {
|
||||
DebugConfigV4 {
|
||||
traffic: value.traffic.into(),
|
||||
cover_traffic: value.cover_traffic.into(),
|
||||
gateway_connection: value.gateway_connection.into(),
|
||||
+76
-67
@@ -1,16 +1,13 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use crate::config::old_config_v1_1_33::{
|
||||
AcknowledgementsV1_1_33, ClientV1_1_33, ConfigV1_1_33, CoverTrafficV1_1_33, DebugConfigV1_1_33,
|
||||
GatewayConnectionV1_1_33, GroupByV1_1_33, ReplySurbsV1_1_33, TopologyStructureV1_1_33,
|
||||
TopologyV1_1_33, TrafficV1_1_33,
|
||||
};
|
||||
use nym_sphinx::{
|
||||
addressing::clients::Recipient,
|
||||
params::{PacketSize, PacketType},
|
||||
use crate::old::v5::{
|
||||
AcknowledgementsV5, ClientV5, ConfigV5, CoverTrafficV5, DebugConfigV5, GatewayConnectionV5,
|
||||
GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
|
||||
};
|
||||
use crate::CountryGroup;
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -56,27 +53,39 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type ConfigV1_1_30 = ConfigV4;
|
||||
pub type ClientV1_1_30 = ClientV4;
|
||||
pub type DebugConfigV1_1_30 = DebugConfigV4;
|
||||
|
||||
pub type TrafficV1_1_30 = TrafficV4;
|
||||
pub type CoverTrafficV1_1_30 = CoverTrafficV4;
|
||||
pub type GatewayConnectionV1_1_30 = GatewayConnectionV4;
|
||||
pub type AcknowledgementsV1_1_30 = AcknowledgementsV4;
|
||||
pub type TopologyV1_1_30 = TopologyV4;
|
||||
pub type ReplySurbsV1_1_30 = ReplySurbsV4;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_30 {
|
||||
pub client: ClientV1_1_30,
|
||||
pub struct ConfigV4 {
|
||||
pub client: ClientV4,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfigV1_1_30,
|
||||
pub debug: DebugConfigV4,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_30> for ConfigV1_1_33 {
|
||||
fn from(value: ConfigV1_1_30) -> Self {
|
||||
ConfigV1_1_33 {
|
||||
client: ClientV1_1_33 {
|
||||
impl From<ConfigV4> for ConfigV5 {
|
||||
fn from(value: ConfigV4) -> Self {
|
||||
ConfigV5 {
|
||||
client: ClientV5 {
|
||||
version: value.client.version,
|
||||
id: value.client.id,
|
||||
disabled_credentials_mode: value.client.disabled_credentials_mode,
|
||||
nyxd_urls: value.client.nyxd_urls,
|
||||
nym_api_urls: value.client.nym_api_urls,
|
||||
},
|
||||
debug: DebugConfigV1_1_33 {
|
||||
traffic: TrafficV1_1_33 {
|
||||
debug: DebugConfigV5 {
|
||||
traffic: TrafficV5 {
|
||||
average_packet_delay: value.debug.traffic.average_packet_delay,
|
||||
message_sending_average_delay: value
|
||||
.debug
|
||||
@@ -90,7 +99,7 @@ impl From<ConfigV1_1_30> for ConfigV1_1_33 {
|
||||
secondary_packet_size: value.debug.traffic.secondary_packet_size,
|
||||
packet_type: value.debug.traffic.packet_type,
|
||||
},
|
||||
cover_traffic: CoverTrafficV1_1_33 {
|
||||
cover_traffic: CoverTrafficV5 {
|
||||
loop_cover_traffic_average_delay: value
|
||||
.debug
|
||||
.cover_traffic
|
||||
@@ -104,18 +113,18 @@ impl From<ConfigV1_1_30> for ConfigV1_1_33 {
|
||||
.cover_traffic
|
||||
.disable_loop_cover_traffic_stream,
|
||||
},
|
||||
gateway_connection: GatewayConnectionV1_1_33 {
|
||||
gateway_connection: GatewayConnectionV5 {
|
||||
gateway_response_timeout: value
|
||||
.debug
|
||||
.gateway_connection
|
||||
.gateway_response_timeout,
|
||||
},
|
||||
acknowledgements: AcknowledgementsV1_1_33 {
|
||||
acknowledgements: AcknowledgementsV5 {
|
||||
average_ack_delay: value.debug.acknowledgements.average_ack_delay,
|
||||
ack_wait_multiplier: value.debug.acknowledgements.ack_wait_multiplier,
|
||||
ack_wait_addition: value.debug.acknowledgements.ack_wait_addition,
|
||||
},
|
||||
topology: TopologyV1_1_33 {
|
||||
topology: TopologyV5 {
|
||||
topology_refresh_rate: value.debug.topology.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.debug.topology.topology_resolution_timeout,
|
||||
disable_refreshing: value.debug.topology.disable_refreshing,
|
||||
@@ -125,7 +134,7 @@ impl From<ConfigV1_1_30> for ConfigV1_1_33 {
|
||||
.max_startup_gateway_waiting_period,
|
||||
topology_structure: value.debug.topology.topology_structure.into(),
|
||||
},
|
||||
reply_surbs: ReplySurbsV1_1_33 {
|
||||
reply_surbs: ReplySurbsV5 {
|
||||
minimum_reply_surb_storage_threshold: value
|
||||
.debug
|
||||
.reply_surbs
|
||||
@@ -169,7 +178,7 @@ impl From<ConfigV1_1_30> for ConfigV1_1_33 {
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ClientV1_1_30 {
|
||||
pub struct ClientV4 {
|
||||
/// Version of the client for which this configuration was created.
|
||||
pub version: String,
|
||||
|
||||
@@ -193,7 +202,7 @@ pub struct ClientV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TrafficV1_1_30 {
|
||||
pub struct TrafficV4 {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
@@ -224,9 +233,9 @@ pub struct TrafficV1_1_30 {
|
||||
pub packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Default for TrafficV1_1_30 {
|
||||
impl Default for TrafficV4 {
|
||||
fn default() -> Self {
|
||||
TrafficV1_1_30 {
|
||||
TrafficV4 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
@@ -239,7 +248,7 @@ impl Default for TrafficV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTrafficV1_1_30 {
|
||||
pub struct CoverTrafficV4 {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -254,9 +263,9 @@ pub struct CoverTrafficV1_1_30 {
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl Default for CoverTrafficV1_1_30 {
|
||||
impl Default for CoverTrafficV4 {
|
||||
fn default() -> Self {
|
||||
CoverTrafficV1_1_30 {
|
||||
CoverTrafficV4 {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
@@ -266,16 +275,16 @@ impl Default for CoverTrafficV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnectionV1_1_30 {
|
||||
pub struct GatewayConnectionV4 {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for GatewayConnectionV1_1_30 {
|
||||
impl Default for GatewayConnectionV4 {
|
||||
fn default() -> Self {
|
||||
GatewayConnectionV1_1_30 {
|
||||
GatewayConnectionV4 {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
@@ -283,7 +292,7 @@ impl Default for GatewayConnectionV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct AcknowledgementsV1_1_30 {
|
||||
pub struct AcknowledgementsV4 {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
@@ -303,9 +312,9 @@ pub struct AcknowledgementsV1_1_30 {
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl Default for AcknowledgementsV1_1_30 {
|
||||
impl Default for AcknowledgementsV4 {
|
||||
fn default() -> Self {
|
||||
AcknowledgementsV1_1_30 {
|
||||
AcknowledgementsV4 {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
@@ -315,7 +324,7 @@ impl Default for AcknowledgementsV1_1_30 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TopologyV1_1_30 {
|
||||
pub struct TopologyV4 {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -338,23 +347,23 @@ pub struct TopologyV1_1_30 {
|
||||
pub max_startup_gateway_waiting_period: Duration,
|
||||
|
||||
/// Specifies the mixnode topology to be used for sending packets.
|
||||
pub topology_structure: TopologyStructureV1_1_30,
|
||||
pub topology_structure: TopologyStructureV4,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TopologyStructureV1_1_30 {
|
||||
pub enum TopologyStructureV4 {
|
||||
#[default]
|
||||
NymApi,
|
||||
GeoAware(GroupByV1_1_30),
|
||||
GeoAware(GroupByV4),
|
||||
}
|
||||
|
||||
impl From<TopologyStructureV1_1_30> for TopologyStructureV1_1_33 {
|
||||
fn from(value: TopologyStructureV1_1_30) -> Self {
|
||||
impl From<TopologyStructureV4> for TopologyStructureV5 {
|
||||
fn from(value: TopologyStructureV4) -> Self {
|
||||
match value {
|
||||
TopologyStructureV1_1_30::NymApi => TopologyStructureV1_1_33::NymApi,
|
||||
TopologyStructureV1_1_30::GeoAware(group_by) => {
|
||||
TopologyStructureV1_1_33::GeoAware(group_by.into())
|
||||
TopologyStructureV4::NymApi => TopologyStructureV5::NymApi,
|
||||
TopologyStructureV4::GeoAware(group_by) => {
|
||||
TopologyStructureV5::GeoAware(group_by.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,44 +371,44 @@ impl From<TopologyStructureV1_1_30> for TopologyStructureV1_1_33 {
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupByV1_1_30 {
|
||||
pub enum GroupByV4 {
|
||||
CountryGroup(CountryGroup),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl From<GroupByV1_1_30> for GroupByV1_1_33 {
|
||||
fn from(value: GroupByV1_1_30) -> Self {
|
||||
impl From<GroupByV4> for GroupByV5 {
|
||||
fn from(value: GroupByV4) -> Self {
|
||||
match value {
|
||||
GroupByV1_1_30::CountryGroup(country) => GroupByV1_1_33::CountryGroup(country),
|
||||
GroupByV1_1_30::NymAddress(addr) => GroupByV1_1_33::NymAddress(addr),
|
||||
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country),
|
||||
GroupByV4::NymAddress(addr) => GroupByV5::NymAddress(addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupByV1_1_30 {
|
||||
impl std::fmt::Display for GroupByV4 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupByV1_1_30::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupByV1_1_30::NymAddress(address) => write!(f, "address: {}", address),
|
||||
GroupByV4::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupByV4::NymAddress(address) => write!(f, "address: {}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyV1_1_30 {
|
||||
impl Default for TopologyV4 {
|
||||
fn default() -> Self {
|
||||
TopologyV1_1_30 {
|
||||
TopologyV4 {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
|
||||
topology_structure: TopologyStructureV1_1_30::default(),
|
||||
topology_structure: TopologyStructureV4::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbsV1_1_30 {
|
||||
pub struct ReplySurbsV4 {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
@@ -437,9 +446,9 @@ pub struct ReplySurbsV1_1_30 {
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbsV1_1_30 {
|
||||
impl Default for ReplySurbsV4 {
|
||||
fn default() -> Self {
|
||||
ReplySurbsV1_1_30 {
|
||||
ReplySurbsV4 {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
@@ -456,22 +465,22 @@ impl Default for ReplySurbsV1_1_30 {
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfigV1_1_30 {
|
||||
pub struct DebugConfigV4 {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: TrafficV1_1_30,
|
||||
pub traffic: TrafficV4,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTrafficV1_1_30,
|
||||
pub cover_traffic: CoverTrafficV4,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnectionV1_1_30,
|
||||
pub gateway_connection: GatewayConnectionV4,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: AcknowledgementsV1_1_30,
|
||||
pub acknowledgements: AcknowledgementsV4,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: TopologyV1_1_30,
|
||||
pub topology: TopologyV4,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbsV1_1_30,
|
||||
pub reply_surbs: ReplySurbsV4,
|
||||
}
|
||||
+67
-59
@@ -1,15 +1,12 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use crate::config::{
|
||||
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, GroupBy,
|
||||
ReplySurbs, Topology, TopologyStructure, Traffic,
|
||||
};
|
||||
use nym_sphinx::{
|
||||
addressing::clients::Recipient,
|
||||
params::{PacketSize, PacketType},
|
||||
use crate::{
|
||||
Acknowledgements, Client, Config, CountryGroup, CoverTraffic, DebugConfig, GatewayConnection,
|
||||
GroupBy, ReplySurbs, Topology, TopologyStructure, Traffic,
|
||||
};
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -55,8 +52,21 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
// aliases for backwards compatibility
|
||||
pub type ConfigV1_1_33 = ConfigV5;
|
||||
pub type ClientV1_1_33 = ClientV5;
|
||||
pub type DebugConfigV1_1_33 = DebugConfigV5;
|
||||
pub type OldGatewayEndpointConfigV1_1_33 = GatewayEndpointConfigV5;
|
||||
|
||||
pub type TrafficV1_1_33 = TrafficV5;
|
||||
pub type CoverTrafficV1_1_33 = CoverTrafficV5;
|
||||
pub type GatewayConnectionV1_1_33 = GatewayConnectionV5;
|
||||
pub type AcknowledgementsV1_1_33 = AcknowledgementsV5;
|
||||
pub type TopologyV1_1_33 = TopologyV5;
|
||||
pub type ReplySurbsV1_1_33 = ReplySurbsV5;
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct OldGatewayEndpointConfigV1_1_33 {
|
||||
pub struct GatewayEndpointConfigV5 {
|
||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||
pub gateway_id: String,
|
||||
@@ -70,15 +80,15 @@ pub struct OldGatewayEndpointConfigV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_33 {
|
||||
pub client: ClientV1_1_33,
|
||||
pub struct ConfigV5 {
|
||||
pub client: ClientV5,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfigV1_1_33,
|
||||
pub debug: DebugConfigV5,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_33> for Config {
|
||||
fn from(value: ConfigV1_1_33) -> Self {
|
||||
impl From<ConfigV5> for Config {
|
||||
fn from(value: ConfigV5) -> Self {
|
||||
Config {
|
||||
client: Client {
|
||||
version: value.client.version,
|
||||
@@ -178,7 +188,7 @@ impl From<ConfigV1_1_33> for Config {
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ClientV1_1_33 {
|
||||
pub struct ClientV5 {
|
||||
/// Version of the client for which this configuration was created.
|
||||
pub version: String,
|
||||
|
||||
@@ -202,7 +212,7 @@ pub struct ClientV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TrafficV1_1_33 {
|
||||
pub struct TrafficV5 {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
@@ -233,9 +243,9 @@ pub struct TrafficV1_1_33 {
|
||||
pub packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Default for TrafficV1_1_33 {
|
||||
impl Default for TrafficV5 {
|
||||
fn default() -> Self {
|
||||
TrafficV1_1_33 {
|
||||
TrafficV5 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
@@ -248,7 +258,7 @@ impl Default for TrafficV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTrafficV1_1_33 {
|
||||
pub struct CoverTrafficV5 {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -263,9 +273,9 @@ pub struct CoverTrafficV1_1_33 {
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl Default for CoverTrafficV1_1_33 {
|
||||
impl Default for CoverTrafficV5 {
|
||||
fn default() -> Self {
|
||||
CoverTrafficV1_1_33 {
|
||||
CoverTrafficV5 {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
@@ -275,16 +285,16 @@ impl Default for CoverTrafficV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnectionV1_1_33 {
|
||||
pub struct GatewayConnectionV5 {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for GatewayConnectionV1_1_33 {
|
||||
impl Default for GatewayConnectionV5 {
|
||||
fn default() -> Self {
|
||||
GatewayConnectionV1_1_33 {
|
||||
GatewayConnectionV5 {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
@@ -292,7 +302,7 @@ impl Default for GatewayConnectionV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct AcknowledgementsV1_1_33 {
|
||||
pub struct AcknowledgementsV5 {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
@@ -312,9 +322,9 @@ pub struct AcknowledgementsV1_1_33 {
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl Default for AcknowledgementsV1_1_33 {
|
||||
impl Default for AcknowledgementsV5 {
|
||||
fn default() -> Self {
|
||||
AcknowledgementsV1_1_33 {
|
||||
AcknowledgementsV5 {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
@@ -324,7 +334,7 @@ impl Default for AcknowledgementsV1_1_33 {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TopologyV1_1_33 {
|
||||
pub struct TopologyV5 {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -347,68 +357,66 @@ pub struct TopologyV1_1_33 {
|
||||
pub max_startup_gateway_waiting_period: Duration,
|
||||
|
||||
/// Specifies the mixnode topology to be used for sending packets.
|
||||
pub topology_structure: TopologyStructureV1_1_33,
|
||||
pub topology_structure: TopologyStructureV5,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TopologyStructureV1_1_33 {
|
||||
pub enum TopologyStructureV5 {
|
||||
#[default]
|
||||
NymApi,
|
||||
GeoAware(GroupByV1_1_33),
|
||||
GeoAware(GroupByV5),
|
||||
}
|
||||
|
||||
impl From<TopologyStructureV1_1_33> for TopologyStructure {
|
||||
fn from(value: TopologyStructureV1_1_33) -> Self {
|
||||
impl From<TopologyStructureV5> for TopologyStructure {
|
||||
fn from(value: TopologyStructureV5) -> Self {
|
||||
match value {
|
||||
TopologyStructureV1_1_33::NymApi => TopologyStructure::NymApi,
|
||||
TopologyStructureV1_1_33::GeoAware(group_by) => {
|
||||
TopologyStructure::GeoAware(group_by.into())
|
||||
}
|
||||
TopologyStructureV5::NymApi => TopologyStructure::NymApi,
|
||||
TopologyStructureV5::GeoAware(group_by) => TopologyStructure::GeoAware(group_by.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupByV1_1_33 {
|
||||
pub enum GroupByV5 {
|
||||
CountryGroup(CountryGroup),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl From<GroupByV1_1_33> for GroupBy {
|
||||
fn from(value: GroupByV1_1_33) -> Self {
|
||||
impl From<GroupByV5> for GroupBy {
|
||||
fn from(value: GroupByV5) -> Self {
|
||||
match value {
|
||||
GroupByV1_1_33::CountryGroup(country) => GroupBy::CountryGroup(country),
|
||||
GroupByV1_1_33::NymAddress(addr) => GroupBy::NymAddress(addr),
|
||||
GroupByV5::CountryGroup(country) => GroupBy::CountryGroup(country),
|
||||
GroupByV5::NymAddress(addr) => GroupBy::NymAddress(addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupByV1_1_33 {
|
||||
impl std::fmt::Display for GroupByV5 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupByV1_1_33::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupByV1_1_33::NymAddress(address) => write!(f, "address: {}", address),
|
||||
GroupByV5::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupByV5::NymAddress(address) => write!(f, "address: {}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyV1_1_33 {
|
||||
impl Default for TopologyV5 {
|
||||
fn default() -> Self {
|
||||
TopologyV1_1_33 {
|
||||
TopologyV5 {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
|
||||
topology_structure: TopologyStructureV1_1_33::default(),
|
||||
topology_structure: TopologyStructureV5::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbsV1_1_33 {
|
||||
pub struct ReplySurbsV5 {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
@@ -450,9 +458,9 @@ pub struct ReplySurbsV1_1_33 {
|
||||
pub surb_mix_hops: Option<u8>,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbsV1_1_33 {
|
||||
impl Default for ReplySurbsV5 {
|
||||
fn default() -> Self {
|
||||
ReplySurbsV1_1_33 {
|
||||
ReplySurbsV5 {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
@@ -470,22 +478,22 @@ impl Default for ReplySurbsV1_1_33 {
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfigV1_1_33 {
|
||||
pub struct DebugConfigV5 {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: TrafficV1_1_33,
|
||||
pub traffic: TrafficV5,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTrafficV1_1_33,
|
||||
pub cover_traffic: CoverTrafficV5,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnectionV1_1_33,
|
||||
pub gateway_connection: GatewayConnectionV5,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: AcknowledgementsV1_1_33,
|
||||
pub acknowledgements: AcknowledgementsV5,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: TopologyV1_1_33,
|
||||
pub topology: TopologyV5,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbsV1_1_33,
|
||||
pub reply_surbs: ReplySurbsV5,
|
||||
}
|
||||
@@ -27,6 +27,12 @@ pub struct GatewayRegistration {
|
||||
pub registration_timestamp: OffsetDateTime,
|
||||
}
|
||||
|
||||
impl GatewayRegistration {
|
||||
pub fn gateway_id(&self) -> identity::PublicKey {
|
||||
self.details.gateway_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a GatewayRegistration> for RawRegisteredGateway {
|
||||
fn from(value: &'a GatewayRegistration) -> Self {
|
||||
RawRegisteredGateway {
|
||||
@@ -298,3 +304,12 @@ pub struct CustomGatewayDetails {
|
||||
pub gateway_id: identity::PublicKey,
|
||||
pub data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl CustomGatewayDetails {
|
||||
pub fn new(gateway_id: identity::PublicKey) -> CustomGatewayDetails {
|
||||
Self {
|
||||
gateway_id,
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ use log::{debug, error, info, warn};
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_gateway_client::{
|
||||
AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter,
|
||||
};
|
||||
@@ -670,6 +670,7 @@ where
|
||||
let self_address = Self::mix_address(&init_res);
|
||||
let ack_key = init_res.client_keys.ack_key();
|
||||
let encryption_keys = init_res.client_keys.encryption_keypair();
|
||||
let identity_keys = init_res.client_keys.identity_keypair();
|
||||
|
||||
// the components are started in very specific order. Unless you know what you are doing,
|
||||
// do not change that.
|
||||
@@ -792,6 +793,7 @@ where
|
||||
|
||||
Ok(BaseClient {
|
||||
address: self_address,
|
||||
identity_keys,
|
||||
client_input: ClientInputStatus::AwaitingProducer {
|
||||
client_input: ClientInput {
|
||||
connection_command_sender: client_connection_tx,
|
||||
@@ -816,6 +818,7 @@ where
|
||||
|
||||
pub struct BaseClient {
|
||||
pub address: Recipient,
|
||||
pub identity_keys: Arc<identity::KeyPair>,
|
||||
pub client_input: ClientInputStatus,
|
||||
pub client_output: ClientOutputStatus,
|
||||
pub client_state: ClientState,
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::error::Error;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use crate::config::disk_persistence::ClientKeysPaths;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
@@ -7,6 +7,8 @@ use nym_metrics::{inc, inc_by};
|
||||
use si_scale::helpers::bibytes2;
|
||||
|
||||
// Metrics server
|
||||
use futures::future::{FusedFuture, OptionFuture};
|
||||
use futures::FutureExt;
|
||||
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||
use http_body_util::Full;
|
||||
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||
@@ -535,6 +537,14 @@ impl PacketStatisticsControl {
|
||||
}
|
||||
|
||||
loop {
|
||||
// it seems at some point tokio changed its select precondition evaluation,
|
||||
// and it's no longer checked before the future is evaluated.
|
||||
let accept_future: OptionFuture<_> = listener
|
||||
.as_ref()
|
||||
.map(|l| l.accept())
|
||||
.map(FutureExt::fuse)
|
||||
.into();
|
||||
|
||||
tokio::select! {
|
||||
stats_event = self.stats_rx.recv() => match stats_event {
|
||||
Some(stats_event) => {
|
||||
@@ -548,10 +558,10 @@ impl PacketStatisticsControl {
|
||||
},
|
||||
// conditional will disable the branch if we're in wasm32-unknown-unknown
|
||||
// use `_` to calm down clippy when running for wasm
|
||||
_result = listener.as_ref().unwrap().accept(), if listener.is_some() => {
|
||||
_result = accept_future, if !accept_future.is_terminated() => {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
|
||||
if let Ok((stream, _)) = _result {
|
||||
if let Some(Ok((stream, _))) = _result {
|
||||
let io = TokioIo::new(stream);
|
||||
|
||||
tokio::task::spawn(async move {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use log::{debug, error, info};
|
||||
use crate::config::GroupBy;
|
||||
use log::{debug, error};
|
||||
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
|
||||
use nym_network_defaults::var_names::EXPLORER_API;
|
||||
use nym_topology::{
|
||||
@@ -10,11 +9,11 @@ use nym_topology::{
|
||||
};
|
||||
use nym_validator_client::client::MixId;
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use tap::TapOptional;
|
||||
use url::Url;
|
||||
|
||||
use crate::config::GroupBy;
|
||||
pub use nym_country_group::CountryGroup;
|
||||
|
||||
const MIN_NODES_PER_LAYER: usize = 1;
|
||||
|
||||
@@ -38,158 +37,6 @@ fn create_explorer_client() -> Option<ExplorerClient> {
|
||||
Some(client)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum CountryGroup {
|
||||
Europe,
|
||||
NorthAmerica,
|
||||
SouthAmerica,
|
||||
Oceania,
|
||||
Asia,
|
||||
Africa,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
// We map contry codes into group, which initially are continent codes to a first approximation,
|
||||
// but we do it manually to reserve the right to tweak this distribution for our purposes.
|
||||
// NOTE: I did this quickly and it's not a complete list of all countries, but only those that
|
||||
// were present in the network at the time. Please add more as needed.
|
||||
fn new(country_code: &str) -> Self {
|
||||
let country_code = country_code.to_uppercase();
|
||||
use CountryGroup::*;
|
||||
match country_code.as_ref() {
|
||||
// Europe
|
||||
"AT" => Europe,
|
||||
"BG" => Europe,
|
||||
"CH" => Europe,
|
||||
"CY" => Europe,
|
||||
"CZ" => Europe,
|
||||
"DE" => Europe,
|
||||
"DK" => Europe,
|
||||
"ES" => Europe,
|
||||
"FI" => Europe,
|
||||
"FR" => Europe,
|
||||
"GB" => Europe,
|
||||
"GR" => Europe,
|
||||
"IE" => Europe,
|
||||
"IT" => Europe,
|
||||
"LT" => Europe,
|
||||
"LU" => Europe,
|
||||
"LV" => Europe,
|
||||
"MD" => Europe,
|
||||
"MT" => Europe,
|
||||
"NL" => Europe,
|
||||
"NO" => Europe,
|
||||
"PL" => Europe,
|
||||
"RO" => Europe,
|
||||
"SE" => Europe,
|
||||
"SK" => Europe,
|
||||
"TR" => Europe,
|
||||
"UA" => Europe,
|
||||
|
||||
// North America
|
||||
"CA" => NorthAmerica,
|
||||
"MX" => NorthAmerica,
|
||||
"US" => NorthAmerica,
|
||||
|
||||
// South America
|
||||
"AR" => SouthAmerica,
|
||||
"BR" => SouthAmerica,
|
||||
"CL" => SouthAmerica,
|
||||
"CO" => SouthAmerica,
|
||||
"CR" => SouthAmerica,
|
||||
"GT" => SouthAmerica,
|
||||
|
||||
// Oceania
|
||||
"AU" => Oceania,
|
||||
|
||||
// Asia
|
||||
"AM" => Asia,
|
||||
"BH" => Asia,
|
||||
"CN" => Asia,
|
||||
"GE" => Asia,
|
||||
"HK" => Asia,
|
||||
"ID" => Asia,
|
||||
"IL" => Asia,
|
||||
"IN" => Asia,
|
||||
"JP" => Asia,
|
||||
"KH" => Asia,
|
||||
"KR" => Asia,
|
||||
"KZ" => Asia,
|
||||
"MY" => Asia,
|
||||
"RU" => Asia,
|
||||
"SG" => Asia,
|
||||
"TH" => Asia,
|
||||
"VN" => Asia,
|
||||
|
||||
// Africa
|
||||
"SC" => Africa,
|
||||
"UG" => Africa,
|
||||
"ZA" => Africa,
|
||||
|
||||
// And group level codes work too
|
||||
"EU" => Europe,
|
||||
"NA" => NorthAmerica,
|
||||
"SA" => SouthAmerica,
|
||||
"OC" => Oceania,
|
||||
"AS" => Asia,
|
||||
"AF" => Africa,
|
||||
|
||||
// And some aliases
|
||||
"EUROPE" => Europe,
|
||||
"NORTHAMERICA" => NorthAmerica,
|
||||
"SOUTHAMERICA" => SouthAmerica,
|
||||
"OCEANIA" => Oceania,
|
||||
"ASIA" => Asia,
|
||||
"AFRICA" => Africa,
|
||||
|
||||
_ => {
|
||||
info!("Unknown country code: {}", country_code);
|
||||
Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CountryGroup {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe => write!(f, "EU"),
|
||||
NorthAmerica => write!(f, "NA"),
|
||||
SouthAmerica => write!(f, "SA"),
|
||||
Oceania => write!(f, "OC"),
|
||||
Asia => write!(f, "AS"),
|
||||
Africa => write!(f, "AF"),
|
||||
Unknown => write!(f, "Unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for CountryGroup {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let group = CountryGroup::new(s);
|
||||
if group == CountryGroup::Unknown {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
#[allow(unused)]
|
||||
fn known(self) -> Option<CountryGroup> {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
|
||||
Unknown => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn group_mixnodes_by_country_code(
|
||||
mixnodes: Vec<PrettyDetailedMixNodeBond>,
|
||||
) -> HashMap<CountryGroup, Vec<MixId>> {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod keys_paths;
|
||||
pub mod old_v1_1_20_2;
|
||||
pub mod old_v1_1_33;
|
||||
|
||||
pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite";
|
||||
pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db";
|
||||
pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.sqlite";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPaths {
|
||||
pub keys: ClientKeysPaths,
|
||||
|
||||
/// Path to the file containing information about gateways used by this client,
|
||||
/// i.e. details such as their public keys, owner addresses or the network information.
|
||||
pub gateway_registrations: PathBuf,
|
||||
|
||||
/// Path to the database containing bandwidth credentials of this client.
|
||||
pub credentials_database: PathBuf,
|
||||
|
||||
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPaths {
|
||||
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
let base_dir = base_data_directory.as_ref();
|
||||
|
||||
CommonClientPaths {
|
||||
credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME),
|
||||
reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME),
|
||||
gateway_registrations: base_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME),
|
||||
keys: ClientKeysPaths::new_base(base_data_directory),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::disk_persistence::old_v1_1_33::{
|
||||
ClientKeysPathsV1_1_33, CommonClientPathsV1_1_33, DEFAULT_GATEWAY_DETAILS_FILENAME,
|
||||
};
|
||||
use crate::error::ClientCoreError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CommonClientPathsV1_1_20_2 {
|
||||
pub keys: ClientKeysPathsV1_1_33,
|
||||
pub credentials_database: PathBuf,
|
||||
pub reply_surb_database: PathBuf,
|
||||
}
|
||||
|
||||
impl CommonClientPathsV1_1_20_2 {
|
||||
pub fn upgrade_default(self) -> Result<CommonClientPathsV1_1_33, ClientCoreError> {
|
||||
let data_dir = self.reply_surb_database.parent().ok_or_else(|| {
|
||||
ClientCoreError::ConfigFileUpgradeFailure {
|
||||
current_version: "1.1.20-2".to_string(),
|
||||
}
|
||||
})?;
|
||||
Ok(CommonClientPathsV1_1_33 {
|
||||
keys: self.keys,
|
||||
gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
|
||||
credentials_database: self.credentials_database,
|
||||
reply_surb_database: self.reply_surb_database,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,602 +1,9 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_sphinx::{
|
||||
addressing::clients::Recipient,
|
||||
params::{PacketSize, PacketType},
|
||||
pub use nym_client_core_config_types::disk_persistence;
|
||||
pub use nym_client_core_config_types::old::{
|
||||
old_config_v1_1_13, old_config_v1_1_20, old_config_v1_1_20_2, old_config_v1_1_30,
|
||||
old_config_v1_1_33,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
pub mod disk_persistence;
|
||||
pub mod old_config_v1_1_13;
|
||||
pub mod old_config_v1_1_20;
|
||||
pub mod old_config_v1_1_20_2;
|
||||
pub mod old_config_v1_1_30;
|
||||
pub mod old_config_v1_1_33;
|
||||
|
||||
// 'DEBUG'
|
||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||
|
||||
const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
|
||||
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
|
||||
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
|
||||
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
|
||||
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
|
||||
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
|
||||
const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead
|
||||
|
||||
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
|
||||
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
|
||||
// bandwidth bridging protocol, we can come back to a smaller timeout value
|
||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
|
||||
|
||||
// reply-surbs related:
|
||||
|
||||
// define when to request
|
||||
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs
|
||||
const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
|
||||
|
||||
// define how much to request at once
|
||||
// clients/client-core/src/client/replies/reply_controller.rs
|
||||
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
|
||||
|
||||
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
|
||||
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10);
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
// 12 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60);
|
||||
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
pub client: Client,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S1, S2>(id: S1, version: S2) -> Self
|
||||
where
|
||||
S1: Into<String>,
|
||||
S2: Into<String>,
|
||||
{
|
||||
Config {
|
||||
client: Client::new_default(id, version),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_client_config(client: Client, debug: DebugConfig) -> Self {
|
||||
Config { client, debug }
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
self.debug.validate()
|
||||
}
|
||||
|
||||
pub fn with_debug_config(mut self, debug: DebugConfig) -> Self {
|
||||
self.debug = debug;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_disabled_credentials(mut self, disabled_credentials_mode: bool) -> Self {
|
||||
self.client.disabled_credentials_mode = disabled_credentials_mode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_nyxd(mut self, urls: Vec<Url>) -> Self {
|
||||
self.client.nyxd_urls = urls;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_custom_nyxd(&mut self, nyxd_urls: Vec<Url>) {
|
||||
self.client.nyxd_urls = nyxd_urls;
|
||||
}
|
||||
|
||||
pub fn with_custom_nym_apis(mut self, nym_api_urls: Vec<Url>) -> Self {
|
||||
self.client.nym_api_urls = nym_api_urls;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
|
||||
self.client.nym_api_urls = nym_api_urls;
|
||||
}
|
||||
|
||||
pub fn with_high_default_traffic_volume(mut self, enabled: bool) -> Self {
|
||||
if enabled {
|
||||
self.set_high_default_traffic_volume();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
|
||||
self.debug.traffic.packet_type = packet_type;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
||||
// basically don't really send cover messages
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay =
|
||||
Duration::from_millis(2_000_000);
|
||||
// 250 "real" messages / s
|
||||
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
|
||||
}
|
||||
|
||||
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_poisson_process()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_poisson_process(&mut self) {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn with_disabled_cover_traffic(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_cover_traffic()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_cover_traffic(&mut self) {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn with_disabled_cover_traffic_with_keepalive(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_cover_traffic_with_keepalive()
|
||||
}
|
||||
self
|
||||
}
|
||||
pub fn set_no_cover_traffic_with_keepalive(&mut self) {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay = Duration::from_secs(5);
|
||||
}
|
||||
|
||||
pub fn with_disabled_topology_refresh(mut self, disable_topology_refresh: bool) -> Self {
|
||||
self.debug.topology.disable_refreshing = disable_topology_refresh;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
|
||||
self.set_topology_structure(topology_structure);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
|
||||
self.debug.topology.topology_structure = topology_structure;
|
||||
}
|
||||
|
||||
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
|
||||
if no_per_hop_delays {
|
||||
self.set_no_per_hop_delays()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_per_hop_delays(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::ZERO;
|
||||
self.debug.acknowledgements.average_ack_delay = Duration::ZERO;
|
||||
}
|
||||
|
||||
pub fn with_secondary_packet_size(mut self, secondary_packet_size: Option<PacketSize>) -> Self {
|
||||
self.set_secondary_packet_size(secondary_packet_size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_secondary_packet_size(&mut self, secondary_packet_size: Option<PacketSize>) {
|
||||
self.debug.traffic.secondary_packet_size = secondary_packet_size;
|
||||
}
|
||||
|
||||
pub fn set_custom_version(&mut self, version: &str) {
|
||||
self.client.version = version.to_string();
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
self.client.id.clone()
|
||||
}
|
||||
|
||||
pub fn get_disabled_credentials_mode(&self) -> bool {
|
||||
self.client.disabled_credentials_mode
|
||||
}
|
||||
|
||||
pub fn get_validator_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nyxd_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nym_api_urls.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Client {
|
||||
/// Version of the client for which this configuration was created.
|
||||
pub version: String,
|
||||
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
pub id: String,
|
||||
|
||||
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
/// to claim bandwidth without presenting bandwidth credentials.
|
||||
// TODO: this should be moved to `debug.gateway_connection`
|
||||
#[serde(default)]
|
||||
pub disabled_credentials_mode: bool,
|
||||
|
||||
/// Addresses to nyxd validators via which the client can communicate with the chain.
|
||||
#[serde(alias = "validator_urls")]
|
||||
pub nyxd_urls: Vec<Url>,
|
||||
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new_default<S1, S2>(id: S1, version: S2) -> Self
|
||||
where
|
||||
S1: Into<String>,
|
||||
S2: Into<String>,
|
||||
{
|
||||
let network = NymNetworkDetails::new_mainnet();
|
||||
let nyxd_urls = network
|
||||
.endpoints
|
||||
.iter()
|
||||
.map(|validator| validator.nyxd_url())
|
||||
.collect();
|
||||
let nym_api_urls = network
|
||||
.endpoints
|
||||
.iter()
|
||||
.filter_map(|validator| validator.api_url())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Client {
|
||||
version: version.into(),
|
||||
id: id.into(),
|
||||
disabled_credentials_mode: true,
|
||||
nyxd_urls,
|
||||
nym_api_urls,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<S: Into<String>>(
|
||||
id: S,
|
||||
disabled_credentials_mode: bool,
|
||||
nyxd_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
) -> Self {
|
||||
Client {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: id.into(),
|
||||
disabled_credentials_mode,
|
||||
nyxd_urls,
|
||||
nym_api_urls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Traffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
|
||||
/// Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
/// poisson distribution.
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
/// Specifies the packet size used for sent messages.
|
||||
/// Do not override it unless you understand the consequences of that change.
|
||||
pub primary_packet_size: PacketSize,
|
||||
|
||||
/// Specifies the optional auxiliary packet size for optimizing message streams.
|
||||
/// Note that its use decreases overall anonymity.
|
||||
/// Do not set it it unless you understand the consequences of that change.
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
pub packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Traffic {
|
||||
pub fn validate(&self) -> bool {
|
||||
if let Some(secondary_packet_size) = self.secondary_packet_size {
|
||||
if secondary_packet_size == PacketSize::AckPacket
|
||||
|| secondary_packet_size == self.primary_packet_size
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Traffic {
|
||||
fn default() -> Self {
|
||||
Traffic {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
packet_type: PacketType::Mix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTraffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
|
||||
/// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
|
||||
/// Only applicable if `secondary_packet_size` is enabled.
|
||||
pub cover_traffic_primary_size_ratio: f64,
|
||||
|
||||
/// Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl Default for CoverTraffic {
|
||||
fn default() -> Self {
|
||||
CoverTraffic {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnection {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for GatewayConnection {
|
||||
fn default() -> Self {
|
||||
GatewayConnection {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Acknowledgements {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
|
||||
/// Value multiplied with the expected round trip time of an acknowledgement packet before
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
/// In an ideal network with 0 latency, this value would have been 1.
|
||||
pub ack_wait_multiplier: f64,
|
||||
|
||||
/// Value added to the expected round trip time of an acknowledgement packet before
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
/// In an ideal network with 0 latency, this value would have been 0.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl Default for Acknowledgements {
|
||||
fn default() -> Self {
|
||||
Acknowledgements {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Topology {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
|
||||
/// During topology refresh, test packets are sent through every single possible network
|
||||
/// path. This timeout determines waiting period until it is decided that the packet
|
||||
/// did not reach its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_resolution_timeout: Duration,
|
||||
|
||||
/// Specifies whether the client should not refresh the network topology after obtaining
|
||||
/// the first valid instance.
|
||||
/// Supersedes `topology_refresh_rate_ms`.
|
||||
pub disable_refreshing: bool,
|
||||
|
||||
/// Defines how long the client is going to wait on startup for its gateway to come online,
|
||||
/// before abandoning the procedure.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub max_startup_gateway_waiting_period: Duration,
|
||||
|
||||
/// Specifies the mixnode topology to be used for sending packets.
|
||||
pub topology_structure: TopologyStructure,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TopologyStructure {
|
||||
#[default]
|
||||
NymApi,
|
||||
GeoAware(GroupBy),
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupBy {
|
||||
CountryGroup(CountryGroup),
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupBy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupBy::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupBy::NymAddress(address) => write!(f, "address: {}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Topology {
|
||||
fn default() -> Self {
|
||||
Topology {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_refreshing: false,
|
||||
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
|
||||
topology_structure: TopologyStructure::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbs {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
|
||||
/// Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
|
||||
/// Defines the minimum number of reply surbs the client would request.
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
|
||||
/// Defines the maximum number of reply surbs the client would request.
|
||||
pub maximum_reply_surb_request_size: u32,
|
||||
|
||||
/// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
|
||||
pub maximum_allowed_reply_surb_request_size: u32,
|
||||
|
||||
/// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
|
||||
/// for more even though in theory they wouldn't need to.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_rerequest_waiting_period: Duration,
|
||||
|
||||
/// Defines maximum amount of time the client is going to wait for reply surbs before
|
||||
/// deciding it's never going to get them and would drop all pending messages
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_drop_waiting_period: Duration,
|
||||
|
||||
/// Defines maximum amount of time given reply surb is going to be valid for.
|
||||
/// This is going to be superseded by key rotation once implemented.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_age: Duration,
|
||||
|
||||
/// Defines maximum amount of time given reply key is going to be valid for.
|
||||
/// This is going to be superseded by key rotation once implemented.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_key_age: Duration,
|
||||
|
||||
/// Specifies the number of mixnet hops the packet should go through. If not specified, then
|
||||
/// the default value is used.
|
||||
pub surb_mix_hops: Option<u8>,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbs {
|
||||
fn default() -> Self {
|
||||
ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_rerequest_waiting_period:
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
surb_mix_hops: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfig {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: Traffic,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTraffic,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnection,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: Acknowledgements,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: Topology,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbs,
|
||||
}
|
||||
|
||||
impl DebugConfig {
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.traffic.validate()
|
||||
}
|
||||
}
|
||||
|
||||
// it could be derived, sure, but I'd rather have an explicit implementation in case we had to change
|
||||
// something manually at some point
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for DebugConfig {
|
||||
fn default() -> Self {
|
||||
DebugConfig {
|
||||
traffic: Default::default(),
|
||||
cover_traffic: Default::default(),
|
||||
gateway_connection: Default::default(),
|
||||
acknowledgements: Default::default(),
|
||||
topology: Default::default(),
|
||||
reply_surbs: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use nym_client_core_config_types::*;
|
||||
|
||||
@@ -201,7 +201,7 @@ where
|
||||
log::debug!("Setting up gateway");
|
||||
match setup {
|
||||
GatewaySetup::MustLoad { gateway_id } => {
|
||||
log::trace!("GatewaySetup::MustLoad with id: {gateway_id:?}");
|
||||
log::debug!("GatewaySetup::MustLoad with id: {gateway_id:?}");
|
||||
use_loaded_gateway_details(key_store, details_store, gateway_id).await
|
||||
}
|
||||
GatewaySetup::New {
|
||||
@@ -209,7 +209,7 @@ where
|
||||
available_gateways,
|
||||
wg_tun_address,
|
||||
} => {
|
||||
log::trace!("GatewaySetup::New with spec: {specification:?}");
|
||||
log::debug!("GatewaySetup::New with spec: {specification:?}");
|
||||
setup_new_gateway(
|
||||
key_store,
|
||||
details_store,
|
||||
@@ -224,7 +224,7 @@ where
|
||||
gateway_details,
|
||||
client_keys: managed_keys,
|
||||
} => {
|
||||
log::trace!("GatewaySetup::ReuseConnection");
|
||||
log::debug!("GatewaySetup::ReuseConnection");
|
||||
Ok(reuse_gateway_connection(
|
||||
authenticated_ephemeral_client,
|
||||
*gateway_details,
|
||||
|
||||
@@ -16,6 +16,8 @@ thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
tokio = { version = "1.24.1", features = ["macros"] }
|
||||
si-scale = "0.2.2"
|
||||
time.workspace = true
|
||||
|
||||
# internal
|
||||
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
||||
@@ -46,10 +48,7 @@ features = ["net", "sync", "time"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||
workspace = true
|
||||
# the choice of this particular tls feature was arbitrary;
|
||||
# if you reckon a different one would be more appropriate, feel free to change it
|
||||
# features = ["native-tls"]
|
||||
features = ["rustls-tls-native-roots"]
|
||||
features = ["rustls-tls-webpki-roots"]
|
||||
|
||||
# wasm-only dependencies
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
||||
|
||||
@@ -79,6 +79,7 @@ impl GatewayConfig {
|
||||
}
|
||||
|
||||
// TODO: this should be refactored into a state machine that keeps track of its authentication state
|
||||
#[derive(Debug)]
|
||||
pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
|
||||
authenticated: bool,
|
||||
disabled_credentials_mode: bool,
|
||||
@@ -441,7 +442,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
|
||||
debug_assert!(self.connection.is_available());
|
||||
log::trace!("Registering gateway");
|
||||
log::debug!("Registering gateway");
|
||||
|
||||
// it's fine to instantiate it here as it's only used once (during authentication or registration)
|
||||
// and putting it into the GatewayClient struct would be a hassle
|
||||
@@ -493,6 +494,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
}
|
||||
log::debug!("Authenticating with gateway");
|
||||
|
||||
// it's fine to instantiate it here as it's only used once (during authentication or registration)
|
||||
// and putting it into the GatewayClient struct would be a hassle
|
||||
@@ -528,6 +530,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
self.authenticated = status;
|
||||
self.bandwidth_remaining = bandwidth_remaining;
|
||||
self.negotiated_protocol = protocol_version;
|
||||
log::debug!("authenticated: {status}, bandwidth remaining: {bandwidth_remaining}");
|
||||
Ok(())
|
||||
}
|
||||
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
|
||||
@@ -540,10 +543,11 @@ impl<C, St> GatewayClient<C, St> {
|
||||
&mut self,
|
||||
) -> Result<Arc<SharedKeys>, GatewayClientError> {
|
||||
if self.authenticated {
|
||||
debug!("Already authenticated");
|
||||
return if let Some(shared_key) = &self.shared_key {
|
||||
Ok(Arc::clone(shared_key))
|
||||
} else {
|
||||
Err(GatewayClientError::AuthenticationFailure)
|
||||
Err(GatewayClientError::AuthenticationFailureWithPreexistingSharedKey)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -849,6 +853,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
// type alias for an ease of use
|
||||
pub type InitGatewayClient = GatewayClient<InitOnly>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InitOnly;
|
||||
|
||||
impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
|
||||
@@ -71,6 +71,9 @@ pub enum GatewayClientError {
|
||||
#[error("Authentication failure")]
|
||||
AuthenticationFailure,
|
||||
|
||||
#[error("Authentication failure with preexisting shared key")]
|
||||
AuthenticationFailureWithPreexistingSharedKey,
|
||||
|
||||
#[error("Timed out")]
|
||||
Timeout,
|
||||
|
||||
|
||||
@@ -10,9 +10,14 @@ use futures::stream::{SplitSink, SplitStream};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::*;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_gateway_requests::ServerResponse;
|
||||
use nym_task::TaskClient;
|
||||
use si_scale::helpers::bibytes2;
|
||||
use std::os::raw::c_int as RawFd;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tungstenite::Message;
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -48,6 +53,22 @@ pub(crate) fn ws_fd(_conn: &WsConn) -> Option<RawFd> {
|
||||
None
|
||||
}
|
||||
|
||||
// disgusting? absolutely, but does the trick for now
|
||||
static LAST_LOGGED_BANDWIDTH_TS: AtomicI64 = AtomicI64::new(0);
|
||||
|
||||
fn maybe_log_bandwidth(remaining: i64) {
|
||||
// SAFETY: this value is always populated with valid timestamps
|
||||
let last =
|
||||
OffsetDateTime::from_unix_timestamp(LAST_LOGGED_BANDWIDTH_TS.load(Ordering::Relaxed))
|
||||
.unwrap();
|
||||
let now = OffsetDateTime::now_utc();
|
||||
if last + Duration::from_secs(10) < now {
|
||||
log::info!("remaining bandwidth: {}", bibytes2(remaining as f64));
|
||||
LAST_LOGGED_BANDWIDTH_TS.store(now.unix_timestamp(), Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PartiallyDelegated {
|
||||
sink_half: SplitSink<WsConn, Message>,
|
||||
delegated_stream: (SplitStreamReceiver, oneshot::Sender<()>),
|
||||
@@ -55,7 +76,10 @@ pub(crate) struct PartiallyDelegated {
|
||||
}
|
||||
|
||||
impl PartiallyDelegated {
|
||||
fn recover_received_plaintexts(ws_msgs: Vec<Message>, shared_key: &SharedKeys) -> Vec<Vec<u8>> {
|
||||
fn recover_received_plaintexts(
|
||||
ws_msgs: Vec<Message>,
|
||||
shared_key: &SharedKeys,
|
||||
) -> Result<Vec<Vec<u8>>, GatewayClientError> {
|
||||
let mut plaintexts = Vec::with_capacity(ws_msgs.len());
|
||||
for ws_msg in ws_msgs {
|
||||
match ws_msg {
|
||||
@@ -73,15 +97,32 @@ impl PartiallyDelegated {
|
||||
// TODO: those can return the "send confirmations" - perhaps it should be somehow worked around?
|
||||
Message::Text(text) => {
|
||||
trace!(
|
||||
"received a text message - probably a response to some previous query! - {}",
|
||||
text
|
||||
"received a text message - probably a response to some previous query! - {text}",
|
||||
);
|
||||
match ServerResponse::try_from(text)
|
||||
.map_err(|_| GatewayClientError::MalformedResponse)?
|
||||
{
|
||||
ServerResponse::Send {
|
||||
remaining_bandwidth,
|
||||
} => maybe_log_bandwidth(remaining_bandwidth),
|
||||
ServerResponse::Error { message } => {
|
||||
error!("gateway failure: {message}");
|
||||
return Err(GatewayClientError::GatewayError(message));
|
||||
}
|
||||
other => {
|
||||
warn!(
|
||||
"received illegal message of type {} in an authenticated client",
|
||||
other.name()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
plaintexts
|
||||
Ok(plaintexts)
|
||||
}
|
||||
|
||||
fn route_socket_messages(
|
||||
@@ -89,7 +130,7 @@ impl PartiallyDelegated {
|
||||
packet_router: &PacketRouter,
|
||||
shared_key: &SharedKeys,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key);
|
||||
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key)?;
|
||||
packet_router.route_received(plaintexts)
|
||||
}
|
||||
|
||||
@@ -129,7 +170,8 @@ impl PartiallyDelegated {
|
||||
};
|
||||
|
||||
if let Err(err) = Self::route_socket_messages(ws_msgs, &packet_router, shared_key.as_ref()) {
|
||||
log::warn!("Route socket messages failed: {err}");
|
||||
log::error!("Route socket messages failed: {err}");
|
||||
break Err(err)
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -221,6 +263,7 @@ impl PartiallyDelegated {
|
||||
// we can either have the stream itself or an option to re-obtain it
|
||||
// by notifying the future owning it to finish the execution and awaiting the result
|
||||
// which should be almost immediate (or an invalid state which should never, ever happen)
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum SocketState {
|
||||
Available(Box<WsConn>),
|
||||
PartiallyDelegated(PartiallyDelegated),
|
||||
|
||||
@@ -24,7 +24,6 @@ nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contr
|
||||
nym-service-provider-directory-common = { path = "../../cosmwasm-smart-contracts/service-provider-directory" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
nym-http-api-client = { path = "../../../common/http-api-client"}
|
||||
thiserror = { workspace = true }
|
||||
log = { workspace = true }
|
||||
@@ -67,6 +66,14 @@ cosmwasm-std = { workspace = true }
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.reqwest]
|
||||
workspace = true
|
||||
features = ["json"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.reqwest]
|
||||
workspace = true
|
||||
features = ["json", "rustls-tls"]
|
||||
|
||||
[dev-dependencies]
|
||||
bip39 = { workspace = true }
|
||||
cosmrs = { workspace = true, features = ["bip32"] }
|
||||
|
||||
@@ -17,7 +17,7 @@ csv = "1.3.0"
|
||||
cw-utils = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
handlebars = "3.0.1"
|
||||
humantime-serde = "1.0"
|
||||
humantime-serde = { workspace = true }
|
||||
inquire = "0.6.2"
|
||||
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
|
||||
log = { workspace = true }
|
||||
|
||||
@@ -148,6 +148,10 @@ pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
bail!("the provided free pass request has too long expiry (expiry is set to on {expiration_date})")
|
||||
}
|
||||
|
||||
if expiration_date < now {
|
||||
bail!("the provided free pass expiry is set in the past!")
|
||||
}
|
||||
|
||||
// issuance start
|
||||
block_until_coconut_is_available(&client).await?;
|
||||
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use csv::WriterBuilder;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::ExecuteMsg;
|
||||
use nym_mixnet_contract_common::ExecuteMsg::{DelegateToMixnode, UndelegateFromMixnode};
|
||||
|
||||
use nym_mixnet_contract_common::PendingEpochEventKind::{Delegate, Undelegate};
|
||||
use nym_validator_client::nyxd::contract_traits::{NymContractsProvider, PagedMixnetQueryClient};
|
||||
use nym_validator_client::nyxd::Coin;
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use crate::utils::pretty_coin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
pub memo: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Input csv files with delegation amounts. Format: (mixID, amount(in NYM))"
|
||||
)]
|
||||
pub input: String,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "An output file path (CSV format) to create or append a log of results to"
|
||||
)]
|
||||
pub output: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InputFileRow {
|
||||
pub mix_id: String,
|
||||
pub amount: Coin,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct InputFileReader {
|
||||
pub rows: Vec<InputFileRow>,
|
||||
}
|
||||
|
||||
impl InputFileReader {
|
||||
pub fn new(path: &str) -> Result<InputFileReader, anyhow::Error> {
|
||||
let file_contents = fs::read_to_string(path)?;
|
||||
let mut rows = Vec::new();
|
||||
let mut mix_id_set = HashSet::new();
|
||||
|
||||
for line in file_contents
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty())
|
||||
{
|
||||
let tokens: Vec<_> = line.split(',').collect();
|
||||
if tokens.len() != 2 {
|
||||
anyhow::bail!("Incorrect format: {}", line);
|
||||
}
|
||||
let mix_id = tokens[0].trim().to_string();
|
||||
let input_amount = tokens[1]
|
||||
.trim()
|
||||
.parse::<u128>()
|
||||
.map_err(|_| anyhow::anyhow!("'{}' has an invalid amount", line))?;
|
||||
|
||||
let micro_nym_amount = input_amount * 1_000_000;
|
||||
|
||||
if !mix_id_set.insert(mix_id.clone()) {
|
||||
anyhow::bail!("Duplicate mix_id found: {}", mix_id);
|
||||
}
|
||||
|
||||
rows.push(InputFileRow {
|
||||
mix_id,
|
||||
amount: Coin {
|
||||
amount: micro_nym_amount,
|
||||
denom: "unym".to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
Ok(InputFileReader { rows })
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to_csv(
|
||||
output_details: Vec<[String; 3]>,
|
||||
output_file: Option<String>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
if let Some(file_path) = output_file {
|
||||
// Determine if the file exists and is not empty
|
||||
let file_exists = fs::metadata(&file_path)
|
||||
.map(|metadata| metadata.len() > 0)
|
||||
.unwrap_or(false);
|
||||
|
||||
// Open the file for appending or creation
|
||||
let file = OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(&file_path)?;
|
||||
|
||||
if !file_exists {
|
||||
let mut wtr = csv::Writer::from_writer(&file);
|
||||
wtr.write_record(["Operation", "Transaction Hash", "Timestamp"])?;
|
||||
wtr.flush()?;
|
||||
}
|
||||
|
||||
let mut wtr = WriterBuilder::new()
|
||||
.has_headers(!file_exists)
|
||||
.from_writer(file);
|
||||
|
||||
// Write the details to the CSV file
|
||||
for detail in output_details {
|
||||
wtr.write_record(&detail)?;
|
||||
}
|
||||
wtr.flush()?;
|
||||
info!("All operations saved to output file");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn fetch_delegation_data(
|
||||
client: &SigningClient,
|
||||
) -> Result<HashMap<String, Coin>, anyhow::Error> {
|
||||
let address = client.address();
|
||||
// Fetch all delegations for the user
|
||||
let delegations = match client.get_all_delegator_delegations(&address).await {
|
||||
Ok(delegations) => delegations,
|
||||
Err(e) => {
|
||||
anyhow::bail!("Error fetching delegations: {}", e)
|
||||
}
|
||||
};
|
||||
|
||||
// Build a map to make it easier to handle delegation data
|
||||
let mut existing_delegation_map: HashMap<String, Coin> = HashMap::new();
|
||||
let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new();
|
||||
|
||||
for delegation in delegations {
|
||||
existing_delegation_map
|
||||
.insert(delegation.mix_id.to_string(), Coin::from(delegation.amount));
|
||||
}
|
||||
|
||||
// Look for pending delegate / undelegate events which might be of interest to us
|
||||
let pending_events = match client.get_all_pending_epoch_events().await {
|
||||
Ok(events) => events,
|
||||
Err(e) => {
|
||||
anyhow::bail!("Error fetching pending epoch events: {}", e);
|
||||
}
|
||||
};
|
||||
|
||||
for event in pending_events {
|
||||
match event.event.kind {
|
||||
// If a pending undelegate tx is found, remove it from delegation map
|
||||
Undelegate { owner, mix_id, .. } => {
|
||||
if owner == address.as_ref()
|
||||
&& existing_delegation_map.contains_key(&mix_id.to_string())
|
||||
{
|
||||
existing_delegation_map.remove(&mix_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// If a pending delegation event is found, gather them to consolidate later
|
||||
Delegate {
|
||||
owner,
|
||||
mix_id,
|
||||
amount,
|
||||
..
|
||||
} => {
|
||||
if owner == address.as_ref() {
|
||||
let mut amount = Coin::from(amount);
|
||||
if let Some(pending_record) = pending_delegation_map.get(&mix_id.to_string()) {
|
||||
amount.amount += pending_record.amount;
|
||||
}
|
||||
pending_delegation_map.insert(mix_id.to_string(), amount);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
// Consolidate pending events into delegation map
|
||||
for (mix_id, amount) in pending_delegation_map {
|
||||
existing_delegation_map
|
||||
.entry(mix_id)
|
||||
.and_modify(|e| e.amount += amount.amount)
|
||||
.or_insert(amount);
|
||||
}
|
||||
|
||||
Ok(existing_delegation_map)
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let existing_delegation_map = fetch_delegation_data(&client)
|
||||
.await
|
||||
.expect("Could not fetch existing delegations");
|
||||
|
||||
let mut delegation_table = Table::new();
|
||||
let mut undelegation_table = Table::new();
|
||||
let mut delegation_msgs: Vec<(ExecuteMsg, Vec<Coin>)> = Vec::new();
|
||||
let mut undelegation_msgs: Vec<(ExecuteMsg, Vec<Coin>)> = Vec::new();
|
||||
|
||||
delegation_table.set_header(["Mix ID", "Input Amount", "Adjusted Amount"]);
|
||||
undelegation_table.set_header(["Mix ID"]);
|
||||
|
||||
for row in &records.rows {
|
||||
let input_amount = row.amount.amount;
|
||||
let existing_delegation_amount = existing_delegation_map
|
||||
.get(&row.mix_id)
|
||||
.map_or(0, |coin| coin.amount);
|
||||
|
||||
match existing_delegation_amount.cmp(&input_amount) {
|
||||
Ordering::Equal => continue, // No action needed if amounts are equal
|
||||
|
||||
Ordering::Less => {
|
||||
// Delegate the difference if the existing delegation is less
|
||||
let difference = Coin {
|
||||
amount: input_amount - existing_delegation_amount,
|
||||
denom: row.amount.denom.clone(),
|
||||
};
|
||||
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
|
||||
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![difference.clone()]));
|
||||
delegation_table.add_row(&[
|
||||
row.mix_id.clone(),
|
||||
pretty_coin(&row.amount),
|
||||
pretty_coin(&difference),
|
||||
]);
|
||||
}
|
||||
|
||||
Ordering::Greater => {
|
||||
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
|
||||
let coins: Vec<Coin> = vec![];
|
||||
undelegation_msgs.push((UndelegateFromMixnode { mix_id }, coins));
|
||||
undelegation_table.add_row(&[row.mix_id.clone()]);
|
||||
|
||||
if row.amount.amount > 0 {
|
||||
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![row.amount.clone()]));
|
||||
delegation_table.add_row(&[
|
||||
row.mix_id.clone(),
|
||||
pretty_coin(&row.amount),
|
||||
pretty_coin(&row.amount),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if delegation_msgs.is_empty() && undelegation_msgs.is_empty() {
|
||||
println!("Nothing to do. Delegations are up-to-date!");
|
||||
return;
|
||||
}
|
||||
|
||||
if !undelegation_msgs.is_empty() {
|
||||
println!("Undelegation records : \n{}\n\n", undelegation_table);
|
||||
}
|
||||
|
||||
if !delegation_msgs.is_empty() {
|
||||
println!("Delegation records : \n{}\n\n", delegation_table);
|
||||
}
|
||||
|
||||
let ans = inquire::Confirm::new("Do you want to continue with the shown operations?")
|
||||
.with_default(false)
|
||||
.with_help_message("You must confirm before the transactions are signed")
|
||||
.prompt();
|
||||
|
||||
if let Err(e) = ans {
|
||||
info!("Aborting, {}...", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(false) = ans {
|
||||
info!("Aborting:: User denied proceeding with signing!");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output_details: Vec<[String; 3]> = Vec::new();
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let now = now
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap();
|
||||
|
||||
let mixnet_contract = client
|
||||
.mixnet_contract_address()
|
||||
.expect("mixnet contract address is not available");
|
||||
|
||||
// Execute all undelegation transactions
|
||||
if !undelegation_msgs.is_empty() {
|
||||
let res = client
|
||||
.execute_multiple(
|
||||
mixnet_contract,
|
||||
undelegation_msgs.clone(),
|
||||
None,
|
||||
format!(
|
||||
"Undelegate from {} nodes via nym-cli",
|
||||
undelegation_msgs.len()
|
||||
),
|
||||
)
|
||||
.await
|
||||
.expect("Could not undelegate!");
|
||||
|
||||
println!(
|
||||
"Undelegation transaction successful : {}",
|
||||
res.transaction_hash
|
||||
);
|
||||
output_details.push([
|
||||
"Undelegate".to_string(),
|
||||
res.transaction_hash.to_string(),
|
||||
now.clone(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Execute all delegation delegations
|
||||
if !delegation_msgs.is_empty() {
|
||||
let res = client
|
||||
.execute_multiple(
|
||||
mixnet_contract,
|
||||
delegation_msgs,
|
||||
None,
|
||||
format!(
|
||||
"Delegatation to {} nodes via nym-cli",
|
||||
undelegation_msgs.len()
|
||||
),
|
||||
)
|
||||
.await
|
||||
.expect("Could not delegate");
|
||||
|
||||
println!(
|
||||
"Delegation transaction successful : {}",
|
||||
res.transaction_hash
|
||||
);
|
||||
output_details.push([
|
||||
"Delegate".to_string(),
|
||||
res.transaction_hash.to_string(),
|
||||
now.clone(),
|
||||
]);
|
||||
}
|
||||
|
||||
if args.output.is_some() {
|
||||
if let Err(e) = write_to_csv(output_details, args.output) {
|
||||
info!("Failed to write to CSV, {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use clap::{Args, Subcommand};
|
||||
pub mod rewards;
|
||||
|
||||
pub mod delegate_to_mixnode;
|
||||
pub mod delegate_to_multiple_mixnodes;
|
||||
pub mod query_for_delegations;
|
||||
pub mod undelegate_from_mixnode;
|
||||
pub mod vesting_delegate_to_mixnode;
|
||||
@@ -26,6 +27,8 @@ pub enum MixnetDelegatorsCommands {
|
||||
Rewards(rewards::MixnetDelegatorsReward),
|
||||
/// Delegate to a mixnode
|
||||
Delegate(delegate_to_mixnode::Args),
|
||||
/// Perform bulk delegations from an input file
|
||||
DelegateMulti(delegate_to_multiple_mixnodes::Args),
|
||||
/// Undelegate from a mixnode
|
||||
Undelegate(undelegate_from_mixnode::Args),
|
||||
/// Delegate to a mixnode with locked tokens
|
||||
|
||||
@@ -328,4 +328,8 @@ impl EpochState {
|
||||
pub fn is_dealing_exchange(&self) -> bool {
|
||||
matches!(self, EpochState::DealingExchange { .. })
|
||||
}
|
||||
|
||||
pub fn is_waiting_initialisation(&self) -> bool {
|
||||
matches!(self, EpochState::WaitingInitialisation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "nym-country-group"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tracing.workspace = true
|
||||
@@ -0,0 +1,158 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum CountryGroup {
|
||||
Europe,
|
||||
NorthAmerica,
|
||||
SouthAmerica,
|
||||
Oceania,
|
||||
Asia,
|
||||
Africa,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
// We map country codes into group, which initially are continent codes to a first approximation,
|
||||
// but we do it manually to reserve the right to tweak this distribution for our purposes.
|
||||
// NOTE: I did this quickly, and it's not a complete list of all countries, but only those that
|
||||
// were present in the network at the time. Please add more as needed.
|
||||
pub fn new(country_code: &str) -> Self {
|
||||
let country_code = country_code.to_uppercase();
|
||||
use CountryGroup::*;
|
||||
match country_code.as_ref() {
|
||||
// Europe
|
||||
"AT" => Europe,
|
||||
"BG" => Europe,
|
||||
"CH" => Europe,
|
||||
"CY" => Europe,
|
||||
"CZ" => Europe,
|
||||
"DE" => Europe,
|
||||
"DK" => Europe,
|
||||
"ES" => Europe,
|
||||
"FI" => Europe,
|
||||
"FR" => Europe,
|
||||
"GB" => Europe,
|
||||
"GR" => Europe,
|
||||
"IE" => Europe,
|
||||
"IT" => Europe,
|
||||
"LT" => Europe,
|
||||
"LU" => Europe,
|
||||
"LV" => Europe,
|
||||
"MD" => Europe,
|
||||
"MT" => Europe,
|
||||
"NL" => Europe,
|
||||
"NO" => Europe,
|
||||
"PL" => Europe,
|
||||
"RO" => Europe,
|
||||
"SE" => Europe,
|
||||
"SK" => Europe,
|
||||
"TR" => Europe,
|
||||
"UA" => Europe,
|
||||
|
||||
// North America
|
||||
"CA" => NorthAmerica,
|
||||
"MX" => NorthAmerica,
|
||||
"US" => NorthAmerica,
|
||||
|
||||
// South America
|
||||
"AR" => SouthAmerica,
|
||||
"BR" => SouthAmerica,
|
||||
"CL" => SouthAmerica,
|
||||
"CO" => SouthAmerica,
|
||||
"CR" => SouthAmerica,
|
||||
"GT" => SouthAmerica,
|
||||
|
||||
// Oceania
|
||||
"AU" => Oceania,
|
||||
|
||||
// Asia
|
||||
"AM" => Asia,
|
||||
"BH" => Asia,
|
||||
"CN" => Asia,
|
||||
"GE" => Asia,
|
||||
"HK" => Asia,
|
||||
"ID" => Asia,
|
||||
"IL" => Asia,
|
||||
"IN" => Asia,
|
||||
"JP" => Asia,
|
||||
"KH" => Asia,
|
||||
"KR" => Asia,
|
||||
"KZ" => Asia,
|
||||
"MY" => Asia,
|
||||
"RU" => Asia,
|
||||
"SG" => Asia,
|
||||
"TH" => Asia,
|
||||
"VN" => Asia,
|
||||
|
||||
// Africa
|
||||
"SC" => Africa,
|
||||
"UG" => Africa,
|
||||
"ZA" => Africa,
|
||||
|
||||
// And group level codes work too
|
||||
"EU" => Europe,
|
||||
"NA" => NorthAmerica,
|
||||
"SA" => SouthAmerica,
|
||||
"OC" => Oceania,
|
||||
"AS" => Asia,
|
||||
"AF" => Africa,
|
||||
|
||||
// And some aliases
|
||||
"EUROPE" => Europe,
|
||||
"NORTHAMERICA" => NorthAmerica,
|
||||
"SOUTHAMERICA" => SouthAmerica,
|
||||
"OCEANIA" => Oceania,
|
||||
"ASIA" => Asia,
|
||||
"AFRICA" => Africa,
|
||||
|
||||
_ => {
|
||||
info!("Unknown country code: {country_code}");
|
||||
Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CountryGroup {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe => write!(f, "EU"),
|
||||
NorthAmerica => write!(f, "NA"),
|
||||
SouthAmerica => write!(f, "SA"),
|
||||
Oceania => write!(f, "OC"),
|
||||
Asia => write!(f, "AS"),
|
||||
Africa => write!(f, "AF"),
|
||||
Unknown => write!(f, "Unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for CountryGroup {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let group = CountryGroup::new(s);
|
||||
if group == CountryGroup::Unknown {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CountryGroup {
|
||||
#[allow(unused)]
|
||||
fn known(self) -> Option<CountryGroup> {
|
||||
use CountryGroup::*;
|
||||
match self {
|
||||
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
|
||||
Unknown => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
ALTER TABLE coconut_credentials
|
||||
RENAME TO old_coconut_credentials;
|
||||
|
||||
CREATE TABLE coconut_credentials
|
||||
(
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
-- introduce a way for us to introduce breaking changes in serialization
|
||||
serialization_revision INTEGER NOT NULL,
|
||||
|
||||
-- the best we can do without enums
|
||||
credential_type TEXT CHECK ( credential_type IN ('BandwidthVoucher', 'FreeBandwidthPass') ) NOT NULL,
|
||||
credential_data BLOB NOT NULL UNIQUE,
|
||||
epoch_id INTEGER NOT NULL,
|
||||
|
||||
-- this field is only really applicable to free passes
|
||||
expired BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE credential_usage
|
||||
RENAME TO old_credential_usage;
|
||||
|
||||
-- for bandwidth vouchers there's going to be only a single entry; for freepasses there can be as many as there are gateways
|
||||
CREATE TABLE credential_usage
|
||||
(
|
||||
credential_id INTEGER NOT NULL REFERENCES coconut_credentials (id),
|
||||
gateway_id_bs58 TEXT NOT NULL,
|
||||
|
||||
-- no matter credential type, we can't spend the same credential with the same gateway multiple times
|
||||
UNIQUE (credential_id, gateway_id_bs58)
|
||||
);
|
||||
|
||||
INSERT INTO coconut_credentials
|
||||
SELECT *
|
||||
FROM old_coconut_credentials;
|
||||
|
||||
|
||||
INSERT INTO credential_usage
|
||||
SELECT *
|
||||
FROM old_credential_usage;
|
||||
|
||||
DROP TABLE old_coconut_credentials;
|
||||
DROP TABLE old_credential_usage;
|
||||
@@ -44,7 +44,7 @@ impl CoconutCredentialManager {
|
||||
r#"
|
||||
SELECT *
|
||||
FROM coconut_credentials
|
||||
WHERE coconut_credentials.credential_type == "FreeBandwidthPass"
|
||||
WHERE coconut_credentials.credential_type == "FreeBandwidthPass" AND coconut_credentials.expired = false
|
||||
AND NOT EXISTS (SELECT 1
|
||||
FROM credential_usage
|
||||
WHERE credential_usage.credential_id = coconut_credentials.id
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use crate::backends::memory::CoconutCredentialManager;
|
||||
use crate::error::StorageError;
|
||||
use crate::models::{StorableIssuedCredential, StoredIssuedCredential};
|
||||
@@ -23,6 +25,12 @@ impl Default for EphemeralStorage {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for EphemeralStorage {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "EphemeralStorage")
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Storage for EphemeralStorage {
|
||||
type StorageError = StorageError;
|
||||
|
||||
@@ -18,4 +18,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("No unused credential in database. You need to buy at least one")]
|
||||
NoCredential,
|
||||
|
||||
#[error("Database unique constraint violation. Is the credential already imported?")]
|
||||
ConstraintUnique,
|
||||
}
|
||||
|
||||
@@ -69,9 +69,21 @@ impl Storage for PersistentStorage {
|
||||
bandwidth_credential.credential_data,
|
||||
bandwidth_credential.epoch_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
.await
|
||||
.map_err(|err| {
|
||||
// There is one error we want to handle specifically.
|
||||
// Check if database_error is `SqliteError` with code 2067 which
|
||||
// means UNIQUE constraint violation
|
||||
if let Some(db_error) = err.as_database_error() {
|
||||
if db_error.code().map_or(false, |code| code == "2067") {
|
||||
StorageError::ConstraintUnique
|
||||
} else {
|
||||
err.into()
|
||||
}
|
||||
} else {
|
||||
err.into()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_next_unspent_credential(
|
||||
|
||||
@@ -8,11 +8,11 @@ use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use nym_coconut::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar, keygen,
|
||||
prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
|
||||
BlindSignRequest, BlindedSerialNumber, BlindedSignature, Bytable, CoconutError, KeyPair,
|
||||
Parameters, PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare,
|
||||
VerificationKey, VerifyCredentialRequest,
|
||||
aggregate_signature_shares, aggregate_signature_shares_and_verify, aggregate_verification_keys,
|
||||
blind_sign, hash_to_scalar, keygen, prepare_blind_sign, prove_bandwidth_credential,
|
||||
verify_credential, Attribute, Base58, BlindSignRequest, BlindedSerialNumber, BlindedSignature,
|
||||
Bytable, CoconutError, KeyPair, Parameters, PrivateAttribute, PublicAttribute, SecretKey,
|
||||
Signature, SignatureShare, VerificationKey, VerifyCredentialRequest,
|
||||
};
|
||||
|
||||
pub const VOUCHER_INFO_TYPE: &str = "BandwidthVoucher";
|
||||
|
||||
@@ -12,7 +12,8 @@ use serde::{Deserialize, Serialize};
|
||||
use time::{Duration, OffsetDateTime, Time};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
pub const MAX_FREE_PASS_VALIDITY: Duration = Duration::WEEK; // 1 week
|
||||
pub const DEFAULT_FREE_PASS_VALIDITY: Duration = Duration::WEEK; // 1 week
|
||||
pub const MAX_FREE_PASS_VALIDITY: Duration = Duration::weeks(12); // 12 weeks
|
||||
|
||||
#[derive(Debug, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
|
||||
pub struct FreePassIssuedData {
|
||||
@@ -77,9 +78,9 @@ impl FreePassIssuanceData {
|
||||
}
|
||||
|
||||
pub fn default_expiry_date() -> OffsetDateTime {
|
||||
// set it to furthest midnight in the future such as it's no more than a week away,
|
||||
// set it to the furthest midnight in the future such as it's no more than a week away,
|
||||
// i.e. if it's currently for example 9:43 on 2nd March 2024, it will set it to 0:00 on 9th March 2024
|
||||
(OffsetDateTime::now_utc() + MAX_FREE_PASS_VALIDITY).replace_time(Time::MIDNIGHT)
|
||||
(OffsetDateTime::now_utc() + DEFAULT_FREE_PASS_VALIDITY).replace_time(Time::MIDNIGHT)
|
||||
}
|
||||
|
||||
pub fn expiry_date_attribute(&self) -> &Attribute {
|
||||
|
||||
@@ -10,18 +10,19 @@ use crate::coconut::bandwidth::{
|
||||
use crate::coconut::utils::scalar_serde_helper;
|
||||
use crate::error::Error;
|
||||
use nym_credentials_interface::{
|
||||
aggregate_signature_shares, hash_to_scalar, prepare_blind_sign, Attribute, BlindedSerialNumber,
|
||||
BlindedSignature, Parameters, PrivateAttribute, PublicAttribute, Signature, SignatureShare,
|
||||
VerificationKey,
|
||||
aggregate_signature_shares, aggregate_signature_shares_and_verify, hash_to_scalar,
|
||||
prepare_blind_sign, Attribute, BlindedSerialNumber, BlindedSignature, Parameters,
|
||||
PrivateAttribute, PublicAttribute, Signature, SignatureShare, VerificationKey,
|
||||
};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
use nym_validator_client::nyxd::{Coin, Hash};
|
||||
use nym_validator_client::signing::AccountData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::OffsetDateTime;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
pub use nym_validator_client::nyxd::{Coin, Hash};
|
||||
|
||||
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
|
||||
pub enum BandwidthCredentialIssuanceDataVariant {
|
||||
Voucher(BandwidthVoucherIssuanceData),
|
||||
@@ -265,6 +266,13 @@ impl IssuanceBandwidthCredential {
|
||||
self.unblind_signature(validator_vk, &signing_data, blinded_signature)
|
||||
}
|
||||
|
||||
pub fn unchecked_aggregate_signature_shares(
|
||||
&self,
|
||||
shares: &[SignatureShare],
|
||||
) -> Result<Signature, Error> {
|
||||
aggregate_signature_shares(shares).map_err(Error::SignatureAggregationError)
|
||||
}
|
||||
|
||||
pub fn aggregate_signature_shares(
|
||||
&self,
|
||||
verification_key: &VerificationKey,
|
||||
@@ -279,7 +287,7 @@ impl IssuanceBandwidthCredential {
|
||||
attributes.extend_from_slice(&private_attributes);
|
||||
attributes.extend_from_slice(&public_attributes);
|
||||
|
||||
aggregate_signature_shares(params, verification_key, &attributes, shares)
|
||||
aggregate_signature_shares_and_verify(params, verification_key, &attributes, shares)
|
||||
.map_err(Error::SignatureAggregationError)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::coconut::utils::scalar_serde_helper;
|
||||
use crate::error::Error;
|
||||
use nym_api_requests::coconut::BlindSignRequestBody;
|
||||
use nym_credentials_interface::{
|
||||
hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, PublicAttribute,
|
||||
hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, CredentialType, PublicAttribute,
|
||||
};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_validator_client::nyxd::{Coin, Hash};
|
||||
@@ -123,6 +123,10 @@ impl BandwidthVoucherIssuanceData {
|
||||
&self.value_prehashed
|
||||
}
|
||||
|
||||
pub fn typ() -> CredentialType {
|
||||
CredentialType::Voucher
|
||||
}
|
||||
|
||||
pub fn tx_hash(&self) -> Hash {
|
||||
self.deposit_tx_hash
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde_helpers;
|
||||
|
||||
#[cfg(feature = "sphinx")]
|
||||
use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::PublicKey;
|
||||
|
||||
pub mod bs58_pubkey {
|
||||
use super::*;
|
||||
use serde_crate::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer>(key: &PublicKey, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_str(&key.to_base58_string())
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<PublicKey, D::Error> {
|
||||
let s = String::deserialize(deserializer)?;
|
||||
PublicKey::from_base58_string(s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,6 @@
|
||||
|
||||
pub mod encryption;
|
||||
pub mod identity;
|
||||
|
||||
pub use encryption as x25519;
|
||||
pub use identity as ed25519;
|
||||
|
||||
@@ -836,7 +836,7 @@ mod tests {
|
||||
let share3 = chunks3.clone().try_into().unwrap();
|
||||
|
||||
let shares = vec![share1, share2, share3];
|
||||
let chunks = &[chunks1, chunks2, chunks3];
|
||||
let chunks = [chunks1, chunks2, chunks3];
|
||||
|
||||
for (i, pk_i) in pks.iter().enumerate() {
|
||||
let mut ciphertext_chunk_i = Vec::with_capacity(NUM_CHUNKS);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "nym-http-api-common"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum.workspace = true
|
||||
bytes = "1.5.0"
|
||||
mime = "0.3.17"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
serde_yaml = "0.9.25"
|
||||
utoipa = { workspace = true }
|
||||
@@ -1,32 +1,13 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use axum::http::{header, HeaderValue, StatusCode};
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::{Json, Router};
|
||||
use axum::Json;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
pub mod v1;
|
||||
|
||||
use crate::http::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
|
||||
use crate::http::state::AppState;
|
||||
pub use nym_node_requests::api as api_requests;
|
||||
use nym_node_requests::routes;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub v1_config: v1::Config,
|
||||
}
|
||||
|
||||
pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Router<AppState> {
|
||||
Router::new().nest(
|
||||
routes::api::V1,
|
||||
v1::routes(config.v1_config, initial_wg_state),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ToSchema)]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
@@ -10,11 +10,11 @@ license.workspace = true
|
||||
[dependencies]
|
||||
bytes = "1.0"
|
||||
futures = { workspace = true }
|
||||
humantime-serde = "1.0"
|
||||
humantime-serde = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rand = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tokio = { version = "1.24.1", features = [
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tokio = { workspace = true, features = [
|
||||
"time",
|
||||
"macros",
|
||||
"rt",
|
||||
@@ -23,6 +23,7 @@ tokio = { version = "1.24.1", features = [
|
||||
] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
url = { workspace = true }
|
||||
time.workspace = true
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-crypto = { path = "../crypto" }
|
||||
@@ -37,3 +38,4 @@ nym-task = { path = "../task" }
|
||||
nym-validator-client = { path = "../client-libs/validator-client" }
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
nym-metrics = { path = "../nym-metrics" }
|
||||
nym-node-http-api = { path = "../../nym-node/nym-node-http-api" }
|
||||
@@ -1,259 +1,35 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use serde::{Serialize, Serializer};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::RwLock;
|
||||
use nym_node_http_api::state::metrics::{SharedVerlocStats, VerlocNodeResult};
|
||||
use std::mem;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct AtomicVerlocResult {
|
||||
inner: Arc<RwLock<VerlocResult>>,
|
||||
pub(crate) trait VerlocStatsUpdateExt {
|
||||
async fn start_new_measurements(&self, nodes_to_test: usize);
|
||||
|
||||
async fn append_measurement_results(&self, new_data: Vec<VerlocNodeResult>);
|
||||
|
||||
async fn finish_measurements(&self);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Default)]
|
||||
pub struct VerlocResult {
|
||||
total_tested: usize,
|
||||
#[serde(with = "humantime_serde")]
|
||||
run_started: Option<std::time::SystemTime>,
|
||||
#[serde(with = "humantime_serde")]
|
||||
run_finished: Option<std::time::SystemTime>,
|
||||
results: Vec<Verloc>,
|
||||
}
|
||||
|
||||
impl AtomicVerlocResult {
|
||||
pub(crate) fn new() -> Self {
|
||||
AtomicVerlocResult {
|
||||
inner: Arc::new(RwLock::new(VerlocResult {
|
||||
total_tested: 0,
|
||||
run_started: None,
|
||||
run_finished: None,
|
||||
results: Vec::new(),
|
||||
})),
|
||||
}
|
||||
impl VerlocStatsUpdateExt for SharedVerlocStats {
|
||||
async fn start_new_measurements(&self, nodes_to_test: usize) {
|
||||
let mut guard = self.write().await;
|
||||
guard.previous_run_data = mem::take(&mut guard.current_run_data);
|
||||
guard.current_run_data.nodes_tested = nodes_to_test;
|
||||
}
|
||||
|
||||
pub(crate) async fn reset_results(&self, new_tested: usize) {
|
||||
let mut write_permit = self.inner.write().await;
|
||||
write_permit.total_tested = new_tested;
|
||||
write_permit.run_started = Some(std::time::SystemTime::now());
|
||||
write_permit.run_finished = None;
|
||||
write_permit.results = Vec::new()
|
||||
}
|
||||
|
||||
pub(crate) async fn append_results(&self, mut new_data: Vec<Verloc>) {
|
||||
let mut write_permit = self.inner.write().await;
|
||||
write_permit.results.append(&mut new_data);
|
||||
async fn append_measurement_results(&self, mut new_data: Vec<VerlocNodeResult>) {
|
||||
let mut write_permit = self.write().await;
|
||||
write_permit.current_run_data.results.append(&mut new_data);
|
||||
// make sure the data always stays in order.
|
||||
// TODO: considering the front of the results is guaranteed to be sorted, should perhaps
|
||||
// a non-default sorting algorithm be used?
|
||||
write_permit.results.sort()
|
||||
write_permit.current_run_data.results.sort()
|
||||
}
|
||||
|
||||
pub(crate) async fn finish_measurements(&self) {
|
||||
self.inner.write().await.run_finished = Some(std::time::SystemTime::now());
|
||||
}
|
||||
|
||||
// Considering that on every read we will need to clone data regardless, let's make our
|
||||
// lives simpler and clone it here rather than deal with lifetime of the permit
|
||||
pub async fn clone_data(&self) -> VerlocResult {
|
||||
self.inner.read().await.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct Verloc {
|
||||
#[serde(serialize_with = "serialize_identity_as_string")]
|
||||
pub identity: identity::PublicKey,
|
||||
pub latest_measurement: Option<Measurement>,
|
||||
}
|
||||
|
||||
fn serialize_identity_as_string<S>(
|
||||
identity: &identity::PublicKey,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&identity.to_base58_string())
|
||||
}
|
||||
|
||||
impl Display for Verloc {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
if let Some(measurement) = self.latest_measurement {
|
||||
write!(f, "{} - {}", self.identity, measurement)
|
||||
} else {
|
||||
write!(f, "{} - COULD NOT MEASURE", self.identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Verloc {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Verloc {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
// if both have measurement, compare measurements
|
||||
// then if only one have measurement, prefer that one
|
||||
// completely ignore identity as it makes no sense to order by it
|
||||
if let Some(self_measurement) = &self.latest_measurement {
|
||||
if let Some(other_measurement) = &other.latest_measurement {
|
||||
self_measurement.cmp(other_measurement)
|
||||
} else {
|
||||
Ordering::Less
|
||||
}
|
||||
} else if other.latest_measurement.is_some() {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Verloc {
|
||||
pub(crate) fn new(
|
||||
identity: identity::PublicKey,
|
||||
latest_measurement: Option<Measurement>,
|
||||
) -> Self {
|
||||
Verloc {
|
||||
identity,
|
||||
latest_measurement,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct Measurement {
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
pub minimum: Duration,
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
pub mean: Duration,
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
pub maximum: Duration,
|
||||
#[serde(serialize_with = "humantime_serde::serialize")]
|
||||
pub standard_deviation: Duration,
|
||||
}
|
||||
|
||||
impl Measurement {
|
||||
pub(crate) fn new(raw_results: &[Duration]) -> Self {
|
||||
let minimum = *raw_results.iter().min().expect("didn't get any results!");
|
||||
let maximum = *raw_results.iter().max().expect("didn't get any results!");
|
||||
|
||||
let mean = Self::duration_mean(raw_results);
|
||||
let standard_deviation = Self::duration_standard_deviation(raw_results, mean);
|
||||
|
||||
Measurement {
|
||||
minimum,
|
||||
mean,
|
||||
maximum,
|
||||
standard_deviation,
|
||||
}
|
||||
}
|
||||
|
||||
fn duration_mean(data: &[Duration]) -> Duration {
|
||||
let sum = data.iter().sum::<Duration>();
|
||||
let count = data.len() as u32;
|
||||
|
||||
sum / count
|
||||
}
|
||||
|
||||
fn duration_standard_deviation(data: &[Duration], mean: Duration) -> Duration {
|
||||
let variance_micros = data
|
||||
.iter()
|
||||
.map(|&value| {
|
||||
// make sure we don't underflow
|
||||
let diff = if mean > value {
|
||||
mean - value
|
||||
} else {
|
||||
value - mean
|
||||
};
|
||||
// we don't need nanos precision
|
||||
let diff_micros = diff.as_micros();
|
||||
diff_micros * diff_micros
|
||||
})
|
||||
.sum::<u128>()
|
||||
/ data.len() as u128;
|
||||
|
||||
// we shouldn't really overflow as our differences shouldn't be larger than couple seconds at the worst possible case scenario
|
||||
let std_deviation_micros = (variance_micros as f64).sqrt() as u64;
|
||||
Duration::from_micros(std_deviation_micros)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Measurement {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"rtt min/avg/max/mdev = {:?} / {:?} / {:?} / {:?}",
|
||||
self.minimum, self.mean, self.maximum, self.standard_deviation
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Measurement {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Measurement {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
// minimum value is most important, then look at standard deviation, then mean and finally maximum
|
||||
let min_cmp = self.minimum.cmp(&other.minimum);
|
||||
if min_cmp != Ordering::Equal {
|
||||
return min_cmp;
|
||||
}
|
||||
let std_dev_cmp = self.standard_deviation.cmp(&other.standard_deviation);
|
||||
if std_dev_cmp != Ordering::Equal {
|
||||
return std_dev_cmp;
|
||||
}
|
||||
let std_dev_cmp = self.mean.cmp(&other.mean);
|
||||
if std_dev_cmp != Ordering::Equal {
|
||||
return std_dev_cmp;
|
||||
}
|
||||
self.maximum.cmp(&other.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sorting_vec_of_verlocs() {
|
||||
let some_identity =
|
||||
identity::PublicKey::from_base58_string("Be9wH7xuXBRJAuV1pC7MALZv6a61RvWQ3SypsNarqTt")
|
||||
.unwrap();
|
||||
let no_measurement = Verloc::new(some_identity, None);
|
||||
let low_min = Verloc::new(
|
||||
some_identity,
|
||||
Some(Measurement {
|
||||
minimum: Duration::from_millis(42),
|
||||
mean: Duration::from_millis(43),
|
||||
maximum: Duration::from_millis(44),
|
||||
standard_deviation: Duration::from_millis(45),
|
||||
}),
|
||||
);
|
||||
let higher_min = Verloc::new(
|
||||
some_identity,
|
||||
Some(Measurement {
|
||||
minimum: Duration::from_millis(420),
|
||||
mean: Duration::from_millis(430),
|
||||
maximum: Duration::from_millis(440),
|
||||
standard_deviation: Duration::from_millis(450),
|
||||
}),
|
||||
);
|
||||
|
||||
let mut vec_verloc = vec![no_measurement, low_min, no_measurement, higher_min];
|
||||
vec_verloc.sort();
|
||||
|
||||
let expected_sorted = vec![low_min, higher_min, no_measurement, no_measurement];
|
||||
assert_eq!(expected_sorted, vec_verloc);
|
||||
async fn finish_measurements(&self) {
|
||||
self.write().await.current_run_data.run_finished = Some(OffsetDateTime::now_utc())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::verloc::listener::PacketListener;
|
||||
@@ -9,6 +9,7 @@ use log::*;
|
||||
use nym_bin_common::version_checker::{self, parse_version};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_network_defaults::mainnet::NYM_API;
|
||||
use nym_node_http_api::state::metrics::{SharedVerlocStats, VerlocNodeResult};
|
||||
use nym_task::TaskClient;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
@@ -20,7 +21,9 @@ use tokio::task::JoinHandle;
|
||||
use tokio::time::sleep;
|
||||
use url::Url;
|
||||
|
||||
pub use crate::verloc::measurement::{AtomicVerlocResult, Verloc, VerlocResult};
|
||||
use measurement::VerlocStatsUpdateExt;
|
||||
|
||||
// pub use crate::verloc::measurement::{AtomicVerlocResult, Verloc, VerlocResult};
|
||||
|
||||
pub mod error;
|
||||
pub(crate) mod listener;
|
||||
@@ -179,7 +182,7 @@ pub struct VerlocMeasurer {
|
||||
// then it definitely cannot be constructed here and probably will need to be passed from outside,
|
||||
// as mixnodes/gateways would already be using an instance of said client.
|
||||
validator_client: nym_validator_client::NymApiClient,
|
||||
results: AtomicVerlocResult,
|
||||
state: SharedVerlocStats,
|
||||
}
|
||||
|
||||
impl VerlocMeasurer {
|
||||
@@ -210,10 +213,14 @@ impl VerlocMeasurer {
|
||||
config.nym_api_urls[0].clone(),
|
||||
),
|
||||
config,
|
||||
results: AtomicVerlocResult::new(),
|
||||
state: SharedVerlocStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_shared_state(&mut self, state: SharedVerlocStats) {
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.config.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single validator API available - it won't be possible to use a different one");
|
||||
@@ -225,10 +232,6 @@ impl VerlocMeasurer {
|
||||
.change_nym_api(self.config.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
pub fn get_verloc_results_pointer(&self) -> AtomicVerlocResult {
|
||||
self.results.clone()
|
||||
}
|
||||
|
||||
fn start_listening(&self) -> JoinHandle<()> {
|
||||
let packet_listener = Arc::clone(&self.packet_listener);
|
||||
tokio::spawn(packet_listener.run())
|
||||
@@ -270,7 +273,7 @@ impl VerlocMeasurer {
|
||||
while !shutdown_listener.is_shutdown() {
|
||||
tokio::select! {
|
||||
measurement_result = measurement_chunk.next() => {
|
||||
let Some(result) = measurement_result else {
|
||||
let Some(result) = measurement_result else {
|
||||
// if the stream has finished, it means we got everything we could have gotten
|
||||
break
|
||||
};
|
||||
@@ -278,18 +281,16 @@ impl VerlocMeasurer {
|
||||
// if we receive JoinError it means the task failed to get executed, so either there's a bigger issue with tokio
|
||||
// or there was a panic inside the task itself. In either case, we should just terminate ourselves.
|
||||
let execution_result = result.expect("the measurement task panicked!");
|
||||
let identity = execution_result.1;
|
||||
|
||||
let measurement_result = match execution_result.0 {
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"Failed to perform measurement for {} - {}",
|
||||
execution_result.1.to_base58_string(),
|
||||
err
|
||||
);
|
||||
debug!("Failed to perform measurement for {identity}: {err}");
|
||||
None
|
||||
}
|
||||
Ok(result) => Some(result),
|
||||
};
|
||||
chunk_results.push(Verloc::new(execution_result.1, measurement_result));
|
||||
chunk_results.push(VerlocNodeResult::new(identity, measurement_result));
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
trace!("Shutdown received while measuring");
|
||||
@@ -299,7 +300,7 @@ impl VerlocMeasurer {
|
||||
}
|
||||
|
||||
// update the results vector with chunks as they become available (by default every 50 nodes)
|
||||
self.results.append_results(chunk_results).await;
|
||||
self.state.append_measurement_results(chunk_results).await;
|
||||
}
|
||||
|
||||
MeasurementOutcome::Done
|
||||
@@ -358,7 +359,7 @@ impl VerlocMeasurer {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// on start of each run remove old results
|
||||
self.results.reset_results(tested_nodes.len()).await;
|
||||
self.state.start_new_measurements(tested_nodes.len()).await;
|
||||
|
||||
if let MeasurementOutcome::Shutdown = self.perform_measurement(tested_nodes).await {
|
||||
log::trace!("Shutting down after aborting measurements");
|
||||
@@ -366,7 +367,7 @@ impl VerlocMeasurer {
|
||||
}
|
||||
|
||||
// write current time to "run finished" field
|
||||
self.results.finish_measurements().await;
|
||||
self.state.finish_measurements().await;
|
||||
|
||||
info!(
|
||||
"Finished performing verloc measurements. The next one will happen in {:?}",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::verloc::error::RttError;
|
||||
use crate::verloc::measurement::Measurement;
|
||||
use crate::verloc::packet::{EchoPacket, ReplyPacket};
|
||||
use log::*;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_node_http_api::state::metrics::VerlocMeasurement;
|
||||
use nym_task::TaskClient;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::net::SocketAddr;
|
||||
@@ -82,7 +82,7 @@ impl PacketSender {
|
||||
pub(super) async fn send_packets_to_node(
|
||||
self: Arc<Self>,
|
||||
tested_node: TestedNode,
|
||||
) -> Result<Measurement, RttError> {
|
||||
) -> Result<VerlocMeasurement, RttError> {
|
||||
let mut shutdown_listener = self.shutdown_listener.fork(tested_node.address.to_string());
|
||||
shutdown_listener.mark_as_success();
|
||||
|
||||
@@ -208,6 +208,6 @@ impl PacketSender {
|
||||
sleep(self.delay_between_packets).await;
|
||||
}
|
||||
|
||||
Ok(Measurement::new(&results))
|
||||
Ok(VerlocMeasurement::new(&results))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,12 @@ pub const VESTING_CONTRACT_ADDRESS: &str =
|
||||
"n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw";
|
||||
|
||||
pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "";
|
||||
pub const GROUP_CONTRACT_ADDRESS: &str = "";
|
||||
pub const MULTISIG_CONTRACT_ADDRESS: &str = "";
|
||||
pub const COCONUT_DKG_CONTRACT_ADDRESS: &str = "";
|
||||
pub const GROUP_CONTRACT_ADDRESS: &str =
|
||||
"n1e2zq4886zzewpvpucmlw8v9p7zv692f6yck4zjzxh699dkcmlrfqk2knsr";
|
||||
pub const MULTISIG_CONTRACT_ADDRESS: &str =
|
||||
"n1txayqfz5g9qww3rlflpg025xd26m9payz96u54x4fe3s2ktz39xqk67gzx";
|
||||
pub const COCONUT_DKG_CONTRACT_ADDRESS: &str =
|
||||
"n19604yflqggs9mk2z26mqygq43q2kr3n932egxx630svywd5mpxjsztfpvx";
|
||||
pub const EPHEMERA_CONTRACT_ADDRESS: &str = "";
|
||||
|
||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
|
||||
|
||||
@@ -6,10 +6,10 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
use nym_coconut::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
|
||||
prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen, verify_credential,
|
||||
verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature,
|
||||
SignatureShare, VerificationKey,
|
||||
aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign,
|
||||
prepare_blind_sign, prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen,
|
||||
verify_credential, verify_partial_blind_signature, Attribute, BlindedSignature, Parameters,
|
||||
Signature, SignatureShare, VerificationKey,
|
||||
};
|
||||
use rand::seq::SliceRandom;
|
||||
use std::ops::Neg;
|
||||
@@ -99,7 +99,7 @@ fn unblind_and_aggregate(
|
||||
let mut attributes = vec![];
|
||||
attributes.extend_from_slice(private_attributes);
|
||||
attributes.extend_from_slice(public_attributes);
|
||||
aggregate_signature_shares(
|
||||
aggregate_signature_shares_and_verify(
|
||||
params,
|
||||
verification_key,
|
||||
&attributes,
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
pub use bls12_381::Scalar;
|
||||
pub use elgamal::elgamal_keygen;
|
||||
pub use elgamal::ElGamalKeyPair;
|
||||
pub use elgamal::PublicKey;
|
||||
pub use error::CoconutError;
|
||||
pub use scheme::aggregation::aggregate_key_shares;
|
||||
pub use scheme::aggregation::aggregate_signature_shares;
|
||||
pub use scheme::aggregation::aggregate_signature_shares_and_verify;
|
||||
pub use scheme::aggregation::aggregate_verification_keys;
|
||||
pub use scheme::issuance::blind_sign;
|
||||
pub use scheme::issuance::prepare_blind_sign;
|
||||
pub use scheme::issuance::sign;
|
||||
pub use scheme::issuance::verify_partial_blind_signature;
|
||||
pub use scheme::issuance::BlindSignRequest;
|
||||
pub use scheme::keygen::keygen;
|
||||
@@ -19,16 +23,19 @@ pub use scheme::keygen::ttp_keygen;
|
||||
pub use scheme::keygen::KeyPair;
|
||||
pub use scheme::keygen::SecretKey;
|
||||
pub use scheme::keygen::VerificationKey;
|
||||
pub use scheme::keygen::VerificationKeyShare;
|
||||
pub use scheme::setup::setup;
|
||||
pub use scheme::setup::Parameters;
|
||||
pub use scheme::verification::check_vk_pairing;
|
||||
pub use scheme::verification::prove_bandwidth_credential;
|
||||
pub use scheme::verification::verify;
|
||||
pub use scheme::verification::verify_credential;
|
||||
pub use scheme::verification::BlindedSerialNumber;
|
||||
pub use scheme::verification::VerifyCredentialRequest;
|
||||
pub use scheme::BlindedSignature;
|
||||
pub use scheme::Signature;
|
||||
pub use scheme::SignatureShare;
|
||||
pub use scheme::SignerIndex;
|
||||
pub use traits::Base58;
|
||||
pub use traits::Bytable;
|
||||
pub use utils::hash_to_scalar;
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::error::{CoconutError, Result};
|
||||
use crate::scheme::verification::check_bilinear_pairing;
|
||||
use crate::scheme::{PartialSignature, Signature, SignatureShare, SignerIndex, VerificationKey};
|
||||
use crate::utils::perform_lagrangian_interpolation_at_origin;
|
||||
use crate::{Attribute, Parameters};
|
||||
use crate::{Attribute, Parameters, VerificationKeyShare};
|
||||
|
||||
pub(crate) trait Aggregatable: Sized {
|
||||
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
|
||||
@@ -80,7 +80,23 @@ pub fn aggregate_verification_keys(
|
||||
Aggregatable::aggregate(keys, indices)
|
||||
}
|
||||
|
||||
pub fn aggregate_key_shares(shares: &[VerificationKeyShare]) -> Result<VerificationKey> {
|
||||
let (keys, indices): (Vec<_>, Vec<_>) = shares
|
||||
.iter()
|
||||
.map(|share| (share.key.clone(), share.index))
|
||||
.unzip();
|
||||
|
||||
aggregate_verification_keys(&keys, Some(&indices))
|
||||
}
|
||||
|
||||
pub fn aggregate_signatures(
|
||||
signatures: &[PartialSignature],
|
||||
indices: Option<&[SignerIndex]>,
|
||||
) -> Result<Signature> {
|
||||
Aggregatable::aggregate(signatures, indices)
|
||||
}
|
||||
|
||||
pub fn aggregate_signatures_and_verify(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
attributes: &[&Attribute],
|
||||
@@ -88,11 +104,7 @@ pub fn aggregate_signatures(
|
||||
indices: Option<&[SignerIndex]>,
|
||||
) -> Result<Signature> {
|
||||
// aggregate the signature
|
||||
|
||||
let signature = match Aggregatable::aggregate(signatures, indices) {
|
||||
Ok(res) => res,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let signature = aggregate_signatures(signatures, indices)?;
|
||||
|
||||
// Verify the signature
|
||||
let alpha = verification_key.alpha;
|
||||
@@ -116,7 +128,16 @@ pub fn aggregate_signatures(
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
pub fn aggregate_signature_shares(
|
||||
pub fn aggregate_signature_shares(shares: &[SignatureShare]) -> Result<Signature> {
|
||||
let (signatures, indices): (Vec<_>, Vec<_>) = shares
|
||||
.iter()
|
||||
.map(|share| (*share.signature(), share.index()))
|
||||
.unzip();
|
||||
|
||||
aggregate_signatures(&signatures, Some(&indices))
|
||||
}
|
||||
|
||||
pub fn aggregate_signature_shares_and_verify(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
attributes: &[&Attribute],
|
||||
@@ -127,7 +148,7 @@ pub fn aggregate_signature_shares(
|
||||
.map(|share| (*share.signature(), share.index()))
|
||||
.unzip();
|
||||
|
||||
aggregate_signatures(
|
||||
aggregate_signatures_and_verify(
|
||||
params,
|
||||
verification_key,
|
||||
attributes,
|
||||
@@ -210,7 +231,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn signature_aggregation_works_for_any_subset_of_signatures() {
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
let params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
@@ -227,12 +248,12 @@ mod tests {
|
||||
|
||||
let sigs = sks
|
||||
.iter()
|
||||
.map(|sk| sign(&mut params, sk, &attributes).unwrap())
|
||||
.map(|sk| sign(¶ms, sk, &attributes).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// aggregating (any) threshold works
|
||||
let aggr_vk_1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap();
|
||||
let aggr_sig1 = aggregate_signatures(
|
||||
let aggr_sig1 = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_1,
|
||||
&attributes,
|
||||
@@ -242,7 +263,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let aggr_vk_2 = aggregate_verification_keys(&vks[2..], Some(&[3, 4, 5])).unwrap();
|
||||
let aggr_sig2 = aggregate_signatures(
|
||||
let aggr_sig2 = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_1,
|
||||
&attributes,
|
||||
@@ -258,7 +279,7 @@ mod tests {
|
||||
|
||||
// aggregating threshold+1 works
|
||||
let aggr_vk_more = aggregate_verification_keys(&vks[1..], Some(&[2, 3, 4, 5])).unwrap();
|
||||
let aggr_more = aggregate_signatures(
|
||||
let aggr_more = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_more,
|
||||
&attributes,
|
||||
@@ -270,7 +291,7 @@ mod tests {
|
||||
|
||||
// aggregating all
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, Some(&[1, 2, 3, 4, 5])).unwrap();
|
||||
let aggr_all = aggregate_signatures(
|
||||
let aggr_all = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
@@ -282,7 +303,7 @@ mod tests {
|
||||
|
||||
// not taking enough points (threshold was 3) should fail
|
||||
let aggr_vk_not_enough = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
|
||||
let aggr_not_enough = aggregate_signatures(
|
||||
let aggr_not_enough = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_not_enough,
|
||||
&attributes,
|
||||
@@ -294,7 +315,7 @@ mod tests {
|
||||
|
||||
// taking wrong index should fail
|
||||
let aggr_vk_bad = aggregate_verification_keys(&vks[2..], Some(&[1, 2, 3])).unwrap();
|
||||
assert!(aggregate_signatures(
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_bad,
|
||||
&attributes,
|
||||
@@ -330,9 +351,14 @@ mod tests {
|
||||
.unzip();
|
||||
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
assert!(
|
||||
aggregate_signatures(¶ms, &aggr_vk_all, &attributes, &signatures, None).is_err()
|
||||
);
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
&signatures,
|
||||
None
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -352,11 +378,15 @@ mod tests {
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
assert!(
|
||||
aggregate_signatures(¶ms, &aggr_vk_all, &attributes, &signatures, Some(&[]))
|
||||
.is_err()
|
||||
);
|
||||
assert!(aggregate_signatures(
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
&signatures,
|
||||
Some(&[])
|
||||
)
|
||||
.is_err());
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
@@ -383,7 +413,7 @@ mod tests {
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
assert!(aggregate_signatures(
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
|
||||
@@ -13,9 +13,8 @@ use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::BlindedSignature;
|
||||
use crate::scheme::SecretKey;
|
||||
use crate::Attribute;
|
||||
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
|
||||
#[cfg(test)]
|
||||
use crate::Signature;
|
||||
|
||||
// TODO: possibly completely remove those two functions.
|
||||
// They only exist to have a simpler and smaller code snippets to test
|
||||
// basic functionalities.
|
||||
@@ -158,6 +157,10 @@ impl BlindSignRequest {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn verify_commitment_hash(&self, public_attributes: &[&Attribute]) -> bool {
|
||||
self.commitment_hash == compute_hash(self.commitment, public_attributes)
|
||||
}
|
||||
|
||||
pub fn get_commitment_hash(&self) -> G1Projective {
|
||||
self.commitment_hash
|
||||
}
|
||||
@@ -426,9 +429,9 @@ pub fn verify_partial_blind_signature(
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
|
||||
pub fn sign(
|
||||
params: &mut Parameters,
|
||||
params: &Parameters,
|
||||
secret_key: &SecretKey,
|
||||
public_attributes: &[&Attribute],
|
||||
) -> Result<Signature> {
|
||||
|
||||
@@ -151,10 +151,6 @@ impl Base58 for SecretKey {}
|
||||
// TODO: perhaps change points to affine representation
|
||||
// to make verification slightly more efficient?
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct VerificationKey {
|
||||
// TODO add gen2 as per the paper or imply it from the fact library is using bls381?
|
||||
pub(crate) alpha: G2Projective,
|
||||
@@ -411,12 +407,23 @@ impl Bytable for VerificationKey {
|
||||
|
||||
impl Base58 for VerificationKey {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VerificationKeyShare {
|
||||
pub key: VerificationKey,
|
||||
pub index: SignerIndex,
|
||||
}
|
||||
|
||||
impl From<(VerificationKey, SignerIndex)> for VerificationKeyShare {
|
||||
fn from(value: (VerificationKey, SignerIndex)) -> Self {
|
||||
VerificationKeyShare {
|
||||
key: value.0,
|
||||
index: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct KeyPair {
|
||||
secret_key: SecretKey,
|
||||
verification_key: VerificationKey,
|
||||
@@ -425,6 +432,12 @@ pub struct KeyPair {
|
||||
pub index: Option<SignerIndex>,
|
||||
}
|
||||
|
||||
impl From<KeyPair> for (SecretKey, VerificationKey) {
|
||||
fn from(value: KeyPair) -> Self {
|
||||
(value.secret_key, value.verification_key)
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKeyPair for KeyPair {
|
||||
type PrivatePemKey = SecretKey;
|
||||
type PublicPemKey = VerificationKey;
|
||||
@@ -461,6 +474,13 @@ impl KeyPair {
|
||||
&self.verification_key
|
||||
}
|
||||
|
||||
pub fn to_verification_key_share(&self) -> Option<VerificationKeyShare> {
|
||||
self.index.map(|index| VerificationKeyShare {
|
||||
key: self.verification_key.clone(),
|
||||
index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
// Schema is coconutkeypair[14]|secret_key_len[8]|secret_key[secret_key_len]|verification_key_len[8]|verification_key[verification_key_len]|signer_index[8] - optional
|
||||
self.to_byte_vec()
|
||||
|
||||
@@ -70,6 +70,11 @@ impl Signature {
|
||||
&self.1
|
||||
}
|
||||
|
||||
pub fn randomise_simple(&self, params: &Parameters) -> Signature {
|
||||
let r = params.random_scalar();
|
||||
Signature(self.0 * r, self.1 * r)
|
||||
}
|
||||
|
||||
pub fn randomise(&self, params: &Parameters) -> (Signature, Scalar) {
|
||||
let r = params.random_scalar();
|
||||
let r_prime = params.random_scalar();
|
||||
@@ -191,7 +196,7 @@ impl BlindedSignature {
|
||||
&self,
|
||||
partial_verification_key: &VerificationKey,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
) -> Result<Signature> {
|
||||
) -> Signature {
|
||||
// parse the signature
|
||||
let h = &self.0;
|
||||
let c = &self.1;
|
||||
@@ -204,7 +209,7 @@ impl BlindedSignature {
|
||||
|
||||
let unblinded_c = c - blinding_removers;
|
||||
|
||||
Ok(Signature(*h, unblinded_c))
|
||||
Signature(*h, unblinded_c)
|
||||
}
|
||||
|
||||
pub fn unblind_and_verify(
|
||||
@@ -216,7 +221,7 @@ impl BlindedSignature {
|
||||
commitment_hash: &G1Projective,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
) -> Result<Signature> {
|
||||
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings)?;
|
||||
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings);
|
||||
unblinded.verify(
|
||||
params,
|
||||
partial_verification_key,
|
||||
@@ -240,6 +245,7 @@ impl BlindedSignature {
|
||||
}
|
||||
|
||||
// perhaps this should take signature by reference? we'll see how it goes
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SignatureShare {
|
||||
signature: Signature,
|
||||
index: SignerIndex,
|
||||
@@ -276,7 +282,9 @@ impl SignatureShare {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::hash_to_scalar;
|
||||
use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys};
|
||||
use crate::scheme::aggregation::{
|
||||
aggregate_signatures_and_verify, aggregate_verification_keys,
|
||||
};
|
||||
use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign};
|
||||
use crate::scheme::keygen::{keygen, ttp_keygen};
|
||||
use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential};
|
||||
@@ -418,13 +426,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn verification_on_two_public_attributes() {
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
let params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
|
||||
let keypair1 = keygen(¶ms);
|
||||
let keypair2 = keygen(¶ms);
|
||||
let sig1 = sign(&mut params, keypair1.secret_key(), &attributes).unwrap();
|
||||
let sig2 = sign(&mut params, keypair2.secret_key(), &attributes).unwrap();
|
||||
let sig1 = sign(¶ms, keypair1.secret_key(), &attributes).unwrap();
|
||||
let sig2 = sign(¶ms, keypair2.secret_key(), &attributes).unwrap();
|
||||
|
||||
assert!(verify(
|
||||
¶ms,
|
||||
@@ -568,9 +576,14 @@ mod tests {
|
||||
attributes.extend_from_slice(&public_attributes);
|
||||
|
||||
let aggr_vk = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
|
||||
let aggr_sig =
|
||||
aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[..2], Some(&[1, 2]))
|
||||
.unwrap();
|
||||
let aggr_sig = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk,
|
||||
&attributes,
|
||||
&sigs[..2],
|
||||
Some(&[1, 2]),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
@@ -590,9 +603,14 @@ mod tests {
|
||||
|
||||
// taking different subset of keys and credentials
|
||||
let aggr_vk = aggregate_verification_keys(&vks[1..], Some(&[2, 3])).unwrap();
|
||||
let aggr_sig =
|
||||
aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[1..], Some(&[2, 3]))
|
||||
.unwrap();
|
||||
let aggr_sig = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk,
|
||||
&attributes,
|
||||
&sigs[1..],
|
||||
Some(&[2, 3]),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::error::{CoconutError, Result};
|
||||
use crate::utils::hash_g1;
|
||||
|
||||
/// System-wide parameters used for the protocol
|
||||
#[derive(Clone)]
|
||||
pub struct Parameters {
|
||||
/// Generator of the G1 group
|
||||
g1: G1Affine,
|
||||
|
||||
@@ -288,7 +288,6 @@ pub fn verify_credential(
|
||||
}
|
||||
|
||||
// Used in tests only
|
||||
#[cfg(test)]
|
||||
pub fn verify(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
|
||||
@@ -75,8 +75,12 @@ pub fn theta_from_keys_and_attributes(
|
||||
attributes.extend_from_slice(public_attributes);
|
||||
|
||||
// Randomize credentials and generate any cryptographic material to verify them
|
||||
let signature =
|
||||
aggregate_signature_shares(params, &verification_key, &attributes, &signature_shares)?;
|
||||
let signature = aggregate_signature_shares_and_verify(
|
||||
params,
|
||||
&verification_key,
|
||||
&attributes,
|
||||
&signature_shares,
|
||||
)?;
|
||||
|
||||
// Generate cryptographic material to verify them
|
||||
let theta = prove_bandwidth_credential(
|
||||
|
||||
@@ -3,3 +3,6 @@
|
||||
|
||||
pub mod clients;
|
||||
pub mod nodes;
|
||||
|
||||
pub use clients::Recipient;
|
||||
pub use nodes::NodeIdentity;
|
||||
|
||||
@@ -16,7 +16,9 @@ const_format = "0.2.32"
|
||||
cosmrs.workspace = true
|
||||
eyre = "0.6.9"
|
||||
futures.workspace = true
|
||||
humantime = "2.1.0"
|
||||
sha2 = "0.10.8"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "time"] }
|
||||
tendermint.workspace = true
|
||||
tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] }
|
||||
@@ -24,13 +26,13 @@ thiserror.workspace = true
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tokio-stream = "0.1.14"
|
||||
tokio-util = { version = "0.7.10", features = ["rt"]}
|
||||
tokio-util = { version = "0.7.10", features = ["rt"] }
|
||||
tracing.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
|
||||
# TEMP
|
||||
nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
|
||||
#nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Nyxd Scraper
|
||||
|
||||
## Pruning
|
||||
|
||||
Similarly to cosmos-sdk, we incorporate pruning into our (scraped) chain data. We attempt to follow their strategies as
|
||||
closely as possible for convenience's sake. Therefore, the following are available:
|
||||
|
||||
### Strategies
|
||||
|
||||
The strategies are configured in `config.toml`, with the format `pruning = "<strategy>"` where the options are:
|
||||
|
||||
* `default`: only the last 362,880 states(approximately 3.5 weeks worth of state) are kept; pruning at 10 block
|
||||
intervals
|
||||
* `nothing`: all historic states will be saved, nothing will be deleted (i.e. archiving node)
|
||||
* `everything`: 2 latest states will be kept; pruning at 10 block intervals.
|
||||
* `custom`: allow pruning options to be manually specified through `pruning.keep_recent`, and `pruning.interval`
|
||||
|
||||
### Custom Pruning
|
||||
|
||||
These are applied if and only if the pruning strategy is `custom`:
|
||||
|
||||
* `pruning.keep_recent`: N means to keep all of the last N blocks
|
||||
* `pruning.interval`: N means to delete old block data from disk every Nth block.
|
||||
@@ -8,6 +8,7 @@ use crate::error::ScraperError;
|
||||
use crate::modules::{BlockModule, MsgModule, TxModule};
|
||||
use crate::rpc_client::RpcClient;
|
||||
use crate::storage::{persist_block, ScraperStorage};
|
||||
use crate::PruningOptions;
|
||||
use futures::StreamExt;
|
||||
use std::collections::{BTreeMap, HashSet, VecDeque};
|
||||
use std::ops::{Add, Range};
|
||||
@@ -18,9 +19,10 @@ use tokio::sync::Notify;
|
||||
use tokio::time::{interval_at, Instant};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing::{debug, error, info, instrument, trace, warn};
|
||||
|
||||
mod helpers;
|
||||
pub(crate) mod pruning;
|
||||
pub(crate) mod types;
|
||||
|
||||
const MISSING_BLOCKS_CHECK_INTERVAL: Duration = Duration::from_secs(30);
|
||||
@@ -40,9 +42,11 @@ impl PendingSync {
|
||||
}
|
||||
|
||||
pub struct BlockProcessor {
|
||||
pruning_options: PruningOptions,
|
||||
cancel: CancellationToken,
|
||||
synced: Arc<Notify>,
|
||||
last_processed_height: u32,
|
||||
last_pruned_height: u32,
|
||||
last_processed_at: Instant,
|
||||
pending_sync: PendingSync,
|
||||
queued_blocks: BTreeMap<u32, BlockToProcess>,
|
||||
@@ -62,6 +66,7 @@ pub struct BlockProcessor {
|
||||
|
||||
impl BlockProcessor {
|
||||
pub async fn new(
|
||||
pruning_options: PruningOptions,
|
||||
cancel: CancellationToken,
|
||||
synced: Arc<Notify>,
|
||||
incoming: UnboundedReceiver<BlockToProcess>,
|
||||
@@ -70,11 +75,17 @@ impl BlockProcessor {
|
||||
rpc_client: RpcClient,
|
||||
) -> Result<Self, ScraperError> {
|
||||
let last_processed = storage.get_last_processed_height().await?;
|
||||
let last_processed_height = last_processed.try_into().unwrap_or_default();
|
||||
|
||||
let last_pruned = storage.get_pruned_height().await?;
|
||||
let last_pruned_height = last_pruned.try_into().unwrap_or_default();
|
||||
|
||||
Ok(BlockProcessor {
|
||||
pruning_options,
|
||||
cancel,
|
||||
synced,
|
||||
last_processed_height: last_processed.try_into().unwrap_or_default(),
|
||||
last_processed_height,
|
||||
last_pruned_height,
|
||||
last_processed_at: Instant::now(),
|
||||
pending_sync: Default::default(),
|
||||
queued_blocks: Default::default(),
|
||||
@@ -131,12 +142,17 @@ impl BlockProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
let commit_start = Instant::now();
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|source| ScraperError::StorageTxCommitFailure { source })?;
|
||||
crate::storage::log_db_operation_time("committing processing tx", commit_start);
|
||||
|
||||
self.last_processed_height = full_info.block.header.height.value() as u32;
|
||||
self.last_processed_at = Instant::now();
|
||||
if let Err(err) = self.maybe_prune_storage().await {
|
||||
error!("failed to prune the storage: {err}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -210,6 +226,61 @@ impl BlockProcessor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn prune_storage(&mut self) -> Result<(), ScraperError> {
|
||||
let keep_recent = self.pruning_options.strategy_keep_recent();
|
||||
let last_to_keep = self.last_processed_height - keep_recent;
|
||||
|
||||
info!(
|
||||
keep_recent,
|
||||
oldest_to_keep = last_to_keep,
|
||||
"pruning the storage"
|
||||
);
|
||||
|
||||
let lowest: u32 = self
|
||||
.storage
|
||||
.lowest_block_height()
|
||||
.await?
|
||||
.unwrap_or_default()
|
||||
.try_into()
|
||||
.unwrap_or_default();
|
||||
|
||||
let to_prune = last_to_keep.saturating_sub(lowest);
|
||||
match to_prune {
|
||||
v if v > 1000 => warn!("approximately {v} blocks worth of data will be pruned"),
|
||||
v if v > 100 => info!("approximately {v} blocks worth of data will be pruned"),
|
||||
0 => trace!("no blocks to prune"),
|
||||
v => debug!("approximately {v} blocks worth of data will be pruned"),
|
||||
}
|
||||
|
||||
if to_prune == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.storage
|
||||
.prune_storage(last_to_keep, self.last_processed_height)
|
||||
.await?;
|
||||
|
||||
self.last_pruned_height = self.last_processed_height;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn maybe_prune_storage(&mut self) -> Result<(), ScraperError> {
|
||||
debug!("checking for storage pruning");
|
||||
|
||||
if self.pruning_options.strategy.is_nothing() {
|
||||
trace!("the current pruning strategy is 'nothing'");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let interval = self.pruning_options.strategy_interval();
|
||||
if self.last_pruned_height + interval <= self.last_processed_height {
|
||||
self.prune_storage().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_incoming(&mut self, block: BlockToProcess) {
|
||||
let height = block.height;
|
||||
|
||||
@@ -279,6 +350,8 @@ impl BlockProcessor {
|
||||
async fn startup_resync(&mut self) -> Result<(), ScraperError> {
|
||||
assert!(self.pending_sync.is_empty());
|
||||
|
||||
self.maybe_prune_storage().await?;
|
||||
|
||||
let latest_block = self.rpc_client.current_block_height().await? as u32;
|
||||
if latest_block > self.last_processed_height && self.last_processed_height != 0 {
|
||||
let request_range = self.last_processed_height + 1..latest_block + 1;
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::ScraperError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const DEFAULT_PRUNING_KEEP_RECENT: u32 = 362880;
|
||||
pub const DEFAULT_PRUNING_INTERVAL: u32 = 10;
|
||||
pub const EVERYTHING_PRUNING_KEEP_RECENT: u32 = 2;
|
||||
pub const EVERYTHING_PRUNING_INTERVAL: u32 = 10;
|
||||
|
||||
/// We follow cosmos-sdk pruning strategies for convenience’s sake.
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PruningStrategy {
|
||||
/// 'Default' strategy defines a pruning strategy where the last 362880 heights are
|
||||
/// kept where to-be pruned heights are pruned at every 10th height.
|
||||
/// The last 362880 heights are kept(approximately 3.5 weeks worth of state) assuming the typical
|
||||
/// block time is 6s. If these values do not match the applications' requirements, use the "custom" option.
|
||||
#[default]
|
||||
Default,
|
||||
|
||||
/// 'Everything' strategy defines a pruning strategy where all committed heights are
|
||||
/// deleted, storing only the current height and last 2 states. To-be pruned heights are
|
||||
/// pruned at every 10th height.
|
||||
Everything,
|
||||
|
||||
/// 'Nothing' strategy defines a pruning strategy where all heights are kept on disk.
|
||||
Nothing,
|
||||
|
||||
/// 'Custom' strategy defines a pruning strategy where the user specifies the pruning.
|
||||
Custom,
|
||||
}
|
||||
|
||||
impl PruningStrategy {
|
||||
pub fn is_custom(&self) -> bool {
|
||||
matches!(self, PruningStrategy::Custom)
|
||||
}
|
||||
|
||||
pub fn is_nothing(&self) -> bool {
|
||||
matches!(self, PruningStrategy::Nothing)
|
||||
}
|
||||
|
||||
pub fn is_everything(&self) -> bool {
|
||||
matches!(self, PruningStrategy::Everything)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct PruningOptions {
|
||||
/// keep_recent defines how many recent heights to keep on disk.
|
||||
pub keep_recent: u32,
|
||||
|
||||
/// interval defines the frequency of removing the pruned heights from the disk.
|
||||
pub interval: u32,
|
||||
|
||||
/// strategy defines the currently used kind of [PruningStrategy].
|
||||
pub strategy: PruningStrategy,
|
||||
}
|
||||
|
||||
impl PruningOptions {
|
||||
pub fn validate(&self) -> Result<(), ScraperError> {
|
||||
// if strategy is not set to custom, other options are meaningless since they won't be applied
|
||||
if !self.strategy.is_custom() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.interval == 0 {
|
||||
return Err(ScraperError::ZeroPruningInterval);
|
||||
}
|
||||
|
||||
if self.interval < EVERYTHING_PRUNING_INTERVAL {
|
||||
return Err(ScraperError::TooSmallPruningInterval {
|
||||
interval: self.interval,
|
||||
});
|
||||
}
|
||||
|
||||
if self.keep_recent < EVERYTHING_PRUNING_KEEP_RECENT {
|
||||
return Err(ScraperError::TooSmallKeepRecent {
|
||||
keep_recent: self.keep_recent,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn nothing() -> Self {
|
||||
PruningOptions {
|
||||
keep_recent: 0,
|
||||
interval: 0,
|
||||
strategy: PruningStrategy::Nothing,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strategy_interval(&self) -> u32 {
|
||||
match self.strategy {
|
||||
PruningStrategy::Default => DEFAULT_PRUNING_INTERVAL,
|
||||
PruningStrategy::Everything => EVERYTHING_PRUNING_INTERVAL,
|
||||
PruningStrategy::Nothing => 0,
|
||||
PruningStrategy::Custom => self.interval,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strategy_keep_recent(&self) -> u32 {
|
||||
match self.strategy {
|
||||
PruningStrategy::Default => DEFAULT_PRUNING_KEEP_RECENT,
|
||||
PruningStrategy::Everything => EVERYTHING_PRUNING_KEEP_RECENT,
|
||||
PruningStrategy::Nothing => 0,
|
||||
PruningStrategy::Custom => self.keep_recent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PruningOptions {
|
||||
fn default() -> Self {
|
||||
PruningOptions {
|
||||
keep_recent: DEFAULT_PRUNING_KEEP_RECENT,
|
||||
interval: DEFAULT_PRUNING_INTERVAL,
|
||||
strategy: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::block_processor::pruning::{
|
||||
EVERYTHING_PRUNING_INTERVAL, EVERYTHING_PRUNING_KEEP_RECENT,
|
||||
};
|
||||
use tendermint::Hash;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc::error::SendError;
|
||||
@@ -122,6 +125,15 @@ pub enum ScraperError {
|
||||
"could not find validator information for {address}; the validator has signed a commit"
|
||||
)]
|
||||
MissingValidatorInfoCommitted { address: String },
|
||||
|
||||
#[error("pruning.interval must not be set to 0. If you want to disable pruning, select pruning.strategy = \"nothing\"")]
|
||||
ZeroPruningInterval,
|
||||
|
||||
#[error("pruning.interval must not be smaller than {}. got: {interval}. for most aggressive pruning, select pruning.strategy = \"everything\"", EVERYTHING_PRUNING_INTERVAL)]
|
||||
TooSmallPruningInterval { interval: u32 },
|
||||
|
||||
#[error("pruning.keep_recent must not be smaller than {}. got: {keep_recent}. for most aggressive pruning, select pruning.strategy = \"everything\"", EVERYTHING_PRUNING_KEEP_RECENT)]
|
||||
TooSmallKeepRecent { keep_recent: u32 },
|
||||
}
|
||||
|
||||
impl<T> From<SendError<T>> for ScraperError {
|
||||
|
||||
@@ -14,6 +14,7 @@ pub(crate) mod rpc_client;
|
||||
pub(crate) mod scraper;
|
||||
pub mod storage;
|
||||
|
||||
pub use block_processor::pruning::{PruningOptions, PruningStrategy};
|
||||
pub use modules::{BlockModule, MsgModule, TxModule};
|
||||
pub use scraper::{Config, NyxdScraper};
|
||||
pub use storage::models;
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::modules::{BlockModule, MsgModule, TxModule};
|
||||
use crate::rpc_client::RpcClient;
|
||||
use crate::scraper::subscriber::ChainSubscriber;
|
||||
use crate::storage::ScraperStorage;
|
||||
use crate::PruningOptions;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{channel, unbounded_channel};
|
||||
@@ -27,6 +28,8 @@ pub struct Config {
|
||||
pub rpc_url: Url,
|
||||
|
||||
pub database_path: PathBuf,
|
||||
|
||||
pub pruning_options: PruningOptions,
|
||||
}
|
||||
|
||||
pub struct NyxdScraperBuilder {
|
||||
@@ -54,6 +57,7 @@ impl NyxdScraperBuilder {
|
||||
processing_tx.clone(),
|
||||
);
|
||||
let mut block_processor = BlockProcessor::new(
|
||||
scraper.config.pruning_options,
|
||||
scraper.cancel_token.clone(),
|
||||
scraper.startup_sync.clone(),
|
||||
processing_rx,
|
||||
@@ -119,6 +123,7 @@ impl NyxdScraper {
|
||||
}
|
||||
|
||||
pub async fn new(config: Config) -> Result<Self, ScraperError> {
|
||||
config.pruning_options.validate()?;
|
||||
let storage = ScraperStorage::init(&config.database_path).await?;
|
||||
|
||||
Ok(NyxdScraper {
|
||||
@@ -160,6 +165,7 @@ impl NyxdScraper {
|
||||
processing_tx.clone(),
|
||||
);
|
||||
let block_processor = BlockProcessor::new(
|
||||
self.config.pruning_options,
|
||||
self.cancel_token.clone(),
|
||||
self.startup_sync.clone(),
|
||||
processing_rx,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::storage::log_db_operation_time;
|
||||
use crate::storage::models::{CommitSignature, Validator};
|
||||
use sqlx::types::time::OffsetDateTime;
|
||||
use sqlx::{Executor, Sqlite};
|
||||
use tokio::time::Instant;
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -25,10 +27,36 @@ impl StorageManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_lowest_block(&self) -> Result<Option<i64>, sqlx::Error> {
|
||||
trace!("get_lowest_block");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT height
|
||||
FROM block
|
||||
ORDER BY height ASC
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_lowest_block", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.height)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_first_block_height_after(
|
||||
&self,
|
||||
time: OffsetDateTime,
|
||||
) -> Result<Option<i64>, sqlx::Error> {
|
||||
trace!("get_first_block_height_after");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT height
|
||||
@@ -41,6 +69,7 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_first_block_height_after", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.height)
|
||||
@@ -53,6 +82,9 @@ impl StorageManager {
|
||||
&self,
|
||||
time: OffsetDateTime,
|
||||
) -> Result<Option<i64>, sqlx::Error> {
|
||||
trace!("get_last_block_height_before");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT height
|
||||
@@ -65,6 +97,7 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_last_block_height_before", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.height)
|
||||
@@ -79,6 +112,9 @@ impl StorageManager {
|
||||
start_height: i64,
|
||||
end_height: i64,
|
||||
) -> Result<i32, sqlx::Error> {
|
||||
trace!("get_signed_between");
|
||||
let start = Instant::now();
|
||||
|
||||
let count = sqlx::query!(
|
||||
r#"
|
||||
SELECT COUNT(*) as count FROM pre_commit
|
||||
@@ -94,6 +130,7 @@ impl StorageManager {
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await?
|
||||
.count;
|
||||
log_db_operation_time("get_signed_between", start);
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
@@ -103,7 +140,10 @@ impl StorageManager {
|
||||
consensus_address: &str,
|
||||
height: i64,
|
||||
) -> Result<Option<CommitSignature>, sqlx::Error> {
|
||||
sqlx::query_as(
|
||||
trace!("get_precommit");
|
||||
let start = Instant::now();
|
||||
|
||||
let res = sqlx::query_as(
|
||||
r#"
|
||||
SELECT * FROM pre_commit
|
||||
WHERE validator_address = ?
|
||||
@@ -113,14 +153,20 @@ impl StorageManager {
|
||||
.bind(consensus_address)
|
||||
.bind(height)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
.await?;
|
||||
log_db_operation_time("get_precommit", start);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_block_validators(
|
||||
&self,
|
||||
height: i64,
|
||||
) -> Result<Vec<Validator>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
trace!("get_block_validators");
|
||||
let start = Instant::now();
|
||||
|
||||
let res = sqlx::query_as!(
|
||||
Validator,
|
||||
r#"
|
||||
SELECT * FROM validator
|
||||
@@ -133,16 +179,28 @@ impl StorageManager {
|
||||
height
|
||||
)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
.await?;
|
||||
log_db_operation_time("get_block_validators", start);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_validators(&self) -> Result<Vec<Validator>, sqlx::Error> {
|
||||
sqlx::query_as("SELECT * FROM validator")
|
||||
trace!("get_validators");
|
||||
let start = Instant::now();
|
||||
|
||||
let res = sqlx::query_as("SELECT * FROM validator")
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
.await?;
|
||||
log_db_operation_time("get_validators", start);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_last_processed_height(&self) -> Result<i64, sqlx::Error> {
|
||||
trace!("get_last_processed_height");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT last_processed_height FROM metadata
|
||||
@@ -150,6 +208,7 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_last_processed_height", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.last_processed_height)
|
||||
@@ -157,6 +216,27 @@ impl StorageManager {
|
||||
Ok(-1)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_pruned_height(&self) -> Result<i64, sqlx::Error> {
|
||||
trace!("get_pruned_height");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT last_pruned_height FROM pruning
|
||||
"#
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
|
||||
log_db_operation_time("get_pruned_height", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.last_pruned_height)
|
||||
} else {
|
||||
Ok(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make those generic over executor so that they could be performed over connection pool and a tx
|
||||
@@ -170,7 +250,8 @@ pub(crate) async fn insert_validator<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert validator");
|
||||
trace!("insert_validator");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -183,6 +264,7 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_validator", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -200,7 +282,8 @@ pub(crate) async fn insert_block<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert block");
|
||||
trace!("insert_block");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -217,6 +300,7 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_block", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -233,7 +317,8 @@ pub(crate) async fn insert_precommit<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert precommit");
|
||||
trace!("insert_precommit");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -249,6 +334,7 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_precommit", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -270,7 +356,8 @@ pub(crate) async fn insert_transaction<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert transaction");
|
||||
trace!("insert_transaction");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -298,6 +385,7 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_transaction", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -313,7 +401,8 @@ pub(crate) async fn insert_message<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert message");
|
||||
trace!("insert_message");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -330,6 +419,7 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_message", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -343,10 +433,100 @@ where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("update_last_processed");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("UPDATE metadata SET last_processed_height = ?", height)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("update_last_processed", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(executor))]
|
||||
pub(crate) async fn update_last_pruned<'a, E>(height: i64, executor: E) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("update_last_pruned");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("UPDATE pruning SET last_pruned_height = ?", height)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("update_last_pruned", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_blocks<'a, E>(oldest_to_keep: i64, executor: E) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_blocks");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("DELETE FROM block WHERE height < ?", oldest_to_keep)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_blocks", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_pre_commits<'a, E>(
|
||||
oldest_to_keep: i64,
|
||||
executor: E,
|
||||
) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_pre_commits");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("DELETE FROM pre_commit WHERE height < ?", oldest_to_keep)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_pre_commits", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_transactions<'a, E>(
|
||||
oldest_to_keep: i64,
|
||||
executor: E,
|
||||
) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_transactions");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
"DELETE FROM \"transaction\" WHERE height < ?",
|
||||
oldest_to_keep
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_transactions", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_messages<'a, E>(
|
||||
oldest_to_keep: i64,
|
||||
executor: E,
|
||||
) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_messages");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("DELETE FROM message WHERE height < ?", oldest_to_keep)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_messages", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ use crate::block_processor::types::{FullBlockInformation, ParsedTransactionRespo
|
||||
use crate::error::ScraperError;
|
||||
use crate::storage::manager::{
|
||||
insert_block, insert_message, insert_precommit, insert_transaction, insert_validator,
|
||||
update_last_processed, StorageManager,
|
||||
prune_blocks, prune_messages, prune_pre_commits, prune_transactions, update_last_processed,
|
||||
update_last_pruned, StorageManager,
|
||||
};
|
||||
use crate::storage::models::{CommitSignature, Validator};
|
||||
use sqlx::types::time::OffsetDateTime;
|
||||
@@ -15,6 +16,7 @@ use std::path::Path;
|
||||
use tendermint::block::{Commit, CommitSig};
|
||||
use tendermint::Block;
|
||||
use tendermint_rpc::endpoint::validators;
|
||||
use tokio::time::Instant;
|
||||
use tracing::{debug, error, info, instrument, trace, warn};
|
||||
|
||||
mod helpers;
|
||||
@@ -28,6 +30,19 @@ pub struct ScraperStorage {
|
||||
pub(crate) manager: StorageManager,
|
||||
}
|
||||
|
||||
pub(crate) fn log_db_operation_time(op_name: &str, start_time: Instant) {
|
||||
let elapsed = start_time.elapsed();
|
||||
let formatted = humantime::format_duration(elapsed);
|
||||
|
||||
match elapsed.as_millis() {
|
||||
v if v > 10000 => error!("{op_name} took {formatted} to execute"),
|
||||
v if v > 1000 => warn!("{op_name} took {formatted} to execute"),
|
||||
v if v > 100 => info!("{op_name} took {formatted} to execute"),
|
||||
v if v > 10 => debug!("{op_name} took {formatted} to execute"),
|
||||
_ => trace!("{op_name} took {formatted} to execute"),
|
||||
}
|
||||
}
|
||||
|
||||
impl ScraperStorage {
|
||||
#[instrument]
|
||||
pub async fn init<P: AsRef<Path> + Debug>(database_path: P) -> Result<Self, ScraperError> {
|
||||
@@ -65,6 +80,32 @@ impl ScraperStorage {
|
||||
Ok(storage)
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn prune_storage(
|
||||
&self,
|
||||
oldest_to_keep: u32,
|
||||
current_height: u32,
|
||||
) -> Result<(), ScraperError> {
|
||||
let start = Instant::now();
|
||||
|
||||
let mut tx = self.begin_processing_tx().await?;
|
||||
|
||||
prune_messages(oldest_to_keep.into(), &mut tx).await?;
|
||||
prune_transactions(oldest_to_keep.into(), &mut tx).await?;
|
||||
prune_pre_commits(oldest_to_keep.into(), &mut tx).await?;
|
||||
prune_blocks(oldest_to_keep.into(), &mut tx).await?;
|
||||
update_last_pruned(current_height.into(), &mut tx).await?;
|
||||
|
||||
let commit_start = Instant::now();
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|source| ScraperError::StorageTxCommitFailure { source })?;
|
||||
log_db_operation_time("committing pruning tx", commit_start);
|
||||
|
||||
log_db_operation_time("pruning storage", start);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn begin_processing_tx(&self) -> Result<StorageTransaction, ScraperError> {
|
||||
debug!("starting storage tx");
|
||||
@@ -75,6 +116,10 @@ impl ScraperStorage {
|
||||
.map_err(|source| ScraperError::StorageTxBeginFailure { source })
|
||||
}
|
||||
|
||||
pub async fn lowest_block_height(&self) -> Result<Option<i64>, ScraperError> {
|
||||
Ok(self.manager.get_lowest_block().await?)
|
||||
}
|
||||
|
||||
pub async fn get_first_block_height_after(
|
||||
&self,
|
||||
time: OffsetDateTime,
|
||||
@@ -155,6 +200,10 @@ impl ScraperStorage {
|
||||
pub async fn get_last_processed_height(&self) -> Result<i64, ScraperError> {
|
||||
Ok(self.manager.get_last_processed_height().await?)
|
||||
}
|
||||
|
||||
pub async fn get_pruned_height(&self) -> Result<i64, ScraperError> {
|
||||
Ok(self.manager.get_pruned_height().await?)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn persist_block(
|
||||
|
||||
@@ -348,7 +348,7 @@ impl TaskClient {
|
||||
"unnamed-TaskClient".to_string()
|
||||
};
|
||||
|
||||
log!(target: target, level, "{msg}")
|
||||
log!(target: target, level, "{}", format!("[{target}] {msg}"))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -474,6 +474,10 @@ impl TaskClient {
|
||||
self.mode.set_should_not_signal_on_drop();
|
||||
}
|
||||
|
||||
pub fn disarm(&mut self) {
|
||||
self.mark_as_success();
|
||||
}
|
||||
|
||||
pub fn send_we_stopped(&mut self, err: SentError) {
|
||||
if self.mode.is_dummy() {
|
||||
return;
|
||||
|
||||
@@ -159,7 +159,7 @@ impl TunDevice {
|
||||
"add",
|
||||
&format!("{}/{}", ipv6, netmaskv6),
|
||||
"dev",
|
||||
&tun.name(),
|
||||
(tun.name()),
|
||||
])
|
||||
.output()?;
|
||||
Ok(tun)
|
||||
|
||||
@@ -50,7 +50,7 @@ pub struct DelegationWithEverything {
|
||||
pub accumulated_by_delegates: Option<DecCoin>,
|
||||
pub accumulated_by_operator: Option<DecCoin>,
|
||||
pub block_height: u64,
|
||||
pub delegated_on_iso_datetime: String,
|
||||
pub delegated_on_iso_datetime: Option<String>,
|
||||
pub cost_params: Option<MixNodeCostParams>,
|
||||
pub avg_uptime_percent: Option<u8>,
|
||||
|
||||
@@ -60,6 +60,8 @@ pub struct DelegationWithEverything {
|
||||
pub uses_vesting_contract_tokens: bool,
|
||||
pub unclaimed_rewards: Option<DecCoin>,
|
||||
|
||||
pub errors: Option<String>,
|
||||
|
||||
// DEPRECATED, IF POSSIBLE TRY TO DISCONTINUE USE OF IT!
|
||||
pub pending_events: Vec<DelegationEvent>,
|
||||
pub mixnode_is_unbonding: Option<bool>,
|
||||
|
||||
@@ -124,15 +124,12 @@ pub struct GatewayNetworkRequesterDetails {
|
||||
pub encryption_key: String,
|
||||
|
||||
pub open_proxy: bool,
|
||||
pub exit_policy: bool,
|
||||
pub enabled_statistics: bool,
|
||||
|
||||
// just a convenience wrapper around all the keys
|
||||
pub address: String,
|
||||
|
||||
pub config_path: String,
|
||||
pub allow_list_path: String,
|
||||
pub unknown_list_path: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for GatewayNetworkRequesterDetails {
|
||||
@@ -146,11 +143,7 @@ impl fmt::Display for GatewayNetworkRequesterDetails {
|
||||
writeln!(f, "\taddress: {}", self.address)?;
|
||||
|
||||
writeln!(f, "\tuses open proxy: {}", self.open_proxy)?;
|
||||
writeln!(f, "\tuses exit policy: {}", self.exit_policy)?;
|
||||
writeln!(f, "\tsends statistics: {}", self.enabled_statistics)?;
|
||||
|
||||
writeln!(f, "\tallow list path: {}", self.allow_list_path)?;
|
||||
writeln!(f, "\tunknown list path: {}", self.unknown_list_path)
|
||||
writeln!(f, "\tsends statistics: {}", self.enabled_statistics)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,3 +171,25 @@ impl fmt::Display for GatewayIpPacketRouterDetails {
|
||||
writeln!(f, "\taddress: {}", self.address)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayWireguardDetails {
|
||||
pub enabled: bool,
|
||||
|
||||
pub announced_port: u16,
|
||||
pub private_network_prefix: u8,
|
||||
}
|
||||
|
||||
impl fmt::Display for GatewayWireguardDetails {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "wireguard:")?;
|
||||
writeln!(f, "\tenabled: {}", self.enabled)?;
|
||||
|
||||
writeln!(f, "\tannounced_port: {}", self.announced_port)?;
|
||||
writeln!(
|
||||
f,
|
||||
"\tprivate_network_prefix: {}",
|
||||
self.private_network_prefix
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use futures::{Sink, Stream};
|
||||
use gloo_net::websocket::futures::WebSocket;
|
||||
use gloo_net::websocket::{Message, WebSocketError};
|
||||
use gloo_utils::errors::JsError;
|
||||
use std::fmt::{self, Formatter};
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
@@ -77,6 +78,12 @@ impl Stream for JSWebsocket {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for JSWebsocket {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "JSWebSocket")
|
||||
}
|
||||
}
|
||||
|
||||
impl Sink<WsMessage> for JSWebsocket {
|
||||
type Error = WsError;
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ log = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-config = { path = "../config" }
|
||||
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
|
||||
# feature-specific dependencies:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user