Compare commits

..

6 Commits

Author SHA1 Message Date
Tommy Verrall 4dc75d3a44 attempt to fix unwrap 2024-03-28 15:26:32 +01:00
Jędrzej Stuczyński de214e9121 fixed NR template 2024-03-28 12:34:30 +00:00
Jędrzej Stuczyński 8a1c537e35 remove explicit deref 2024-03-28 10:15:49 +00:00
Jędrzej Stuczyński 14b2a29083 config migration for removing allow.list 2024-03-28 10:15:49 +00:00
Jędrzej Stuczyński 1c5ae7d8bd moved and renamed NR old config structs 2024-03-28 10:15:49 +00:00
Jędrzej Stuczyński f1737c2bb3 removed the usage of allow.list 2024-03-28 10:15:48 +00:00
343 changed files with 5764 additions and 21269 deletions
@@ -112,7 +112,6 @@ 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
@@ -131,7 +130,6 @@ 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
@@ -30,7 +30,6 @@ 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 }}
@@ -39,7 +38,6 @@ 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 }}
@@ -83,7 +81,6 @@ jobs:
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
retention-days: 30
- id: create-release
@@ -102,7 +99,6 @@ 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' }}
-14
View File
@@ -4,20 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [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
+126 -426
View File
File diff suppressed because it is too large Load Diff
+2 -8
View File
@@ -24,7 +24,6 @@ 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",
@@ -42,7 +41,6 @@ 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",
@@ -52,7 +50,6 @@ members = [
"common/execute",
"common/exit-policy",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
"common/ip-packet-requests",
"common/ledger",
@@ -90,7 +87,6 @@ members = [
"common/wasm/utils",
"common/wireguard",
"common/wireguard-types",
"documentation/autodoc",
"explorer-api",
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
@@ -108,7 +104,6 @@ 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",
@@ -122,7 +117,8 @@ members = [
"wasm/client",
# "wasm/full-nym-wasm",
"wasm/mix-fetch",
"wasm/node-tester", "documentation/autodoc",
"wasm/node-tester",
"common/nym-metrics",
]
default-members = [
@@ -136,7 +132,6 @@ default-members = [
"tools/nymvisor",
"explorer-api",
"nym-validator-rewarder",
"nym-node"
]
exclude = [
@@ -172,7 +167,6 @@ dotenvy = "0.15.6"
futures = "0.3.28"
generic-array = "0.14.7"
getrandom = "0.2.10"
humantime-serde = "1.1.1"
hyper = "0.14.27"
k256 = "0.13"
lazy_static = "1.4.0"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.34"
version = "1.1.33"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+91 -291
View File
@@ -674,13 +674,13 @@
}
},
"node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
"dev": true,
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
"content-type": "~1.0.4",
"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.2",
"raw-body": "2.5.1",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
@@ -793,19 +793,13 @@
}
},
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"dependencies": {
"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"
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -1036,18 +1030,18 @@
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"dev": true,
"engines": {
"node": ">= 0.6"
@@ -1143,23 +1137,6 @@
"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",
@@ -1381,27 +1358,6 @@
"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",
@@ -1507,17 +1463,17 @@
}
},
"node_modules/express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"dev": true,
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"body-parser": "1.20.1",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
@@ -1775,28 +1731,20 @@
}
},
"node_modules/function-bind": {
"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"
}
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"dev": true,
"dependencies": {
"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"
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -1876,18 +1824,6 @@
"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",
@@ -1919,34 +1855,10 @@
"node": ">=8"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"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"
},
"funding": {
"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==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
"dev": true,
"engines": {
"node": ">= 0.4"
@@ -1955,18 +1867,6 @@
"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",
@@ -2750,9 +2650,9 @@
}
},
"node_modules/object-inspect": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3138,9 +3038,9 @@
}
},
"node_modules/raw-body": {
"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==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"dev": true,
"dependencies": {
"bytes": "3.1.2",
@@ -3513,23 +3413,6 @@
"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",
@@ -3570,18 +3453,14 @@
}
},
"node_modules/side-channel": {
"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==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4",
"object-inspect": "^1.13.1"
},
"engines": {
"node": ">= 0.4"
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -5151,13 +5030,13 @@
"dev": true
},
"body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
"dev": true,
"requires": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
@@ -5165,7 +5044,7 @@
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"raw-body": "2.5.2",
"raw-body": "2.5.1",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
@@ -5243,16 +5122,13 @@
"dev": true
},
"call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"requires": {
"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"
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"camel-case": {
@@ -5418,15 +5294,15 @@
}
},
"content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"dev": true
},
"cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"dev": true
},
"cookie-signature": {
@@ -5501,17 +5377,6 @@
"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",
@@ -5681,21 +5546,6 @@
"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",
@@ -5776,17 +5626,17 @@
}
},
"express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"dev": true,
"requires": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"body-parser": "1.20.1",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
@@ -5987,22 +5837,20 @@
"optional": true
},
"function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"dev": true,
"requires": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
},
"get-stream": {
@@ -6060,15 +5908,6 @@
}
}
},
"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",
@@ -6094,36 +5933,12 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"has-property-descriptors": {
"version": "1.0.2",
"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==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
"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",
@@ -6700,9 +6515,9 @@
"dev": true
},
"object-inspect": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
"dev": true
},
"object-is": {
@@ -6988,9 +6803,9 @@
"dev": true
},
"raw-body": {
"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==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"dev": true,
"requires": {
"bytes": "3.1.2",
@@ -7275,20 +7090,6 @@
"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",
@@ -7320,15 +7121,14 @@
"dev": true
},
"side-channel": {
"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==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"requires": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4",
"object-inspect": "^1.13.1"
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"signal-exit": {
@@ -8,7 +8,5 @@ use nym_client_core::cli_helpers::client_import_credential::{
};
pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> {
import_credential::<CliNativeClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
import_credential::<CliNativeClient, _>(args).await
}
-3
View File
@@ -23,9 +23,6 @@ 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 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.34"
version = "1.1.33"
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,7 +10,5 @@ use nym_client_core::cli_helpers::client_import_credential::{
pub(crate) async fn execute(
args: CommonClientImportCredentialArgs,
) -> Result<(), Socks5ClientError> {
import_credential::<CliSocks5Client, _>(args).await?;
println!("successfully imported credential!");
Ok(())
import_credential::<CliSocks5Client, _>(args).await
}
-3
View File
@@ -23,9 +23,6 @@ pub enum Socks5ClientError {
#[error(transparent)]
ClientCoreError(#[from] ClientCoreError),
#[error(transparent)]
ConfigUpgradeFailure(#[from] nym_client_core::config::ConfigUpgradeFailure),
#[error(transparent)]
NymIdError(#[from] NymIdError),
}
-1
View File
@@ -18,7 +18,6 @@ pub mod acquire;
pub mod error;
mod utils;
#[derive(Debug)]
pub struct BandwidthController<C, St> {
storage: St,
client: C,
+1
View File
@@ -8,6 +8,7 @@ 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 -3
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::io::IsTerminal;
#[cfg(feature = "tracing")]
pub use opentelemetry;
@@ -15,7 +14,7 @@ pub use tracing_subscriber;
#[cfg(feature = "tracing")]
pub use tracing_tree;
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingSettings {
// well, we need to implement something here at some point...
@@ -121,7 +120,7 @@ pub fn banner(crate_name: &str, crate_version: &str) -> String {
}
pub fn maybe_print_banner(crate_name: &str, crate_version: &str) {
if std::io::stdout().is_terminal() {
if atty::is(atty::Stream::Stdout) {
println!("{}", banner(crate_name, crate_version))
}
}
+1 -3
View File
@@ -15,7 +15,7 @@ bs58 = { workspace = true }
cfg-if = "1.0.0"
clap = { workspace = true, optional = true }
futures = { workspace = true }
humantime-serde = { workspace = true }
humantime-serde = "1.0"
log = { workspace = true }
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { workspace = true, features = ["derive"] }
@@ -34,7 +34,6 @@ 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" }
@@ -48,7 +47,6 @@ 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" }
@@ -1,26 +0,0 @@
[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"]
@@ -1,9 +0,0 @@
// 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;
@@ -1,37 +0,0 @@
// 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,
})
}
}
@@ -1,10 +0,0 @@
// 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,
}
-602
View File
@@ -1,602 +0,0 @@
// 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);
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
}
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,
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(),
}
}
}
@@ -1,15 +0,0 @@
// 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;
@@ -27,12 +27,6 @@ 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 {
@@ -304,12 +298,3 @@ 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,
}
}
}
@@ -7,7 +7,7 @@ use std::error::Error;
use tokio::sync::Mutex;
#[cfg(not(target_arch = "wasm32"))]
use crate::config::disk_persistence::ClientKeysPaths;
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
#[cfg(not(target_arch = "wasm32"))]
use nym_crypto::asymmetric::{encryption, identity};
#[cfg(not(target_arch = "wasm32"))]
@@ -7,8 +7,6 @@ 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")))]
@@ -537,14 +535,6 @@ 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) => {
@@ -556,37 +546,37 @@ impl PacketStatisticsControl {
break;
}
},
// conditional will disable the branch if we're in wasm32-unknown-unknown
// use `_` to calm down clippy when running for wasm
_result = accept_future, if !accept_future.is_terminated() => {
cfg_if::cfg_if! {
if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
if let Some(Ok((stream, _))) = _result {
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(serve_metrics))
.await
{
log::warn!("Error serving connection: {:?}", err);
}
});
} else {
log::warn!("Error accepting connection");
_ = async {
if let Some(ref listener) = listener {
if let Ok((stream, _)) = listener.accept().await {
cfg_if::cfg_if! {
if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(serve_metrics))
.await
{
log::warn!("Error serving connection: {:?}", err);
}
});
}
}
}
} else {
let _ = futures::future::pending::<()>().await;
}
}
}, if listener.is_some() => {
},
_ = snapshot_interval.tick() => {
self.update_history();
self.update_rates();
}
},
_ = report_interval.tick() => {
self.report_rates();
self.check_for_notable_events();
self.report_counters();
}
},
_ = shutdown.recv_with_delay() => {
log::trace!("PacketStatisticsControl: Received shutdown");
break;
@@ -1,5 +1,6 @@
use crate::config::GroupBy;
use log::{debug, error};
use std::{collections::HashMap, fmt};
use log::{debug, error, info};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
@@ -9,11 +10,11 @@ use nym_topology::{
};
use nym_validator_client::client::MixId;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use tap::TapOptional;
use url::Url;
pub use nym_country_group::CountryGroup;
use crate::config::GroupBy;
const MIN_NODES_PER_LAYER: usize = 1;
@@ -37,6 +38,158 @@ 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,53 +1,15 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - 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,43 @@
// 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),
}
}
}
@@ -0,0 +1,33 @@
// 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,20 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::disk_persistence::ClientKeysPaths;
use crate::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME};
use crate::error::ConfigUpgradeFailure;
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME};
use crate::error::ClientCoreError;
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 ClientKeysPathsV2 {
pub struct ClientKeysPathsV1_1_33 {
/// Path to file containing private identity key.
pub private_identity_key_file: PathBuf,
@@ -36,7 +32,7 @@ pub struct ClientKeysPathsV2 {
pub ack_key_file: PathBuf,
}
impl ClientKeysPathsV2 {
impl ClientKeysPathsV1_1_33 {
pub fn upgrade(self) -> ClientKeysPaths {
ClientKeysPaths {
private_identity_key_file: self.private_identity_key_file,
@@ -50,8 +46,8 @@ impl ClientKeysPathsV2 {
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommonClientPathsV2 {
pub keys: ClientKeysPathsV2,
pub struct CommonClientPathsV1_1_33 {
pub keys: ClientKeysPathsV1_1_33,
/// 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.
@@ -64,16 +60,15 @@ pub struct CommonClientPathsV2 {
pub reply_surb_database: PathBuf,
}
impl CommonClientPathsV2 {
impl CommonClientPathsV1_1_33 {
// 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, ConfigUpgradeFailure> {
let data_dir = self
.gateway_details
.parent()
.ok_or_else(|| ConfigUpgradeFailure {
pub fn upgrade_default(self) -> Result<CommonClientPaths, ClientCoreError> {
let data_dir = self.gateway_details.parent().ok_or_else(|| {
ClientCoreError::ConfigFileUpgradeFailure {
current_version: "1.1.33".to_string(),
})?;
}
})?;
Ok(CommonClientPaths {
keys: self.keys.upgrade(),
+599 -6
View File
@@ -1,9 +1,602 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
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 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::*;
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(),
}
}
}
@@ -1,28 +1,23 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
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,
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,
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 {
@@ -43,28 +38,28 @@ impl From<ExtendedPacketSize> for PacketSize {
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1<T> {
pub client: ClientV2<T>,
pub struct OldConfigV1_1_13<T> {
pub client: ClientV1_1_20<T>,
#[serde(default)]
pub logging: LoggingV1,
pub logging: OldLoggingV1_1_13,
#[serde(default)]
pub debug: DebugConfigV1,
pub debug: OldDebugConfigV1_1_13,
}
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingV1 {}
pub struct OldLoggingV1_1_13 {}
impl From<LoggingV1> for LoggingV2 {
fn from(_value: LoggingV1) -> Self {
LoggingV2 {}
impl From<OldLoggingV1_1_13> for LoggingV1_1_20 {
fn from(_value: OldLoggingV1_1_13) -> Self {
LoggingV1_1_20 {}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV1 {
pub struct OldDebugConfigV1_1_13 {
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
@@ -119,10 +114,10 @@ pub struct DebugConfigV1 {
pub maximum_reply_key_age: Duration,
}
impl From<DebugConfigV1> for DebugConfigV2 {
fn from(value: DebugConfigV1) -> Self {
DebugConfigV2 {
traffic: TrafficV2 {
impl From<OldDebugConfigV1_1_13> for DebugConfigV1_1_20 {
fn from(value: OldDebugConfigV1_1_13) -> Self {
DebugConfigV1_1_20 {
traffic: TrafficV1_1_20 {
average_packet_delay: value.average_packet_delay,
message_sending_average_delay: value.message_sending_average_delay,
disable_main_poisson_packet_distribution: value
@@ -130,25 +125,25 @@ impl From<DebugConfigV1> for DebugConfigV2 {
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: value.use_extended_packet_size.map(Into::into),
},
cover_traffic: CoverTrafficV2 {
cover_traffic: CoverTrafficV1_1_20 {
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
..CoverTrafficV2::default()
..CoverTrafficV1_1_20::default()
},
gateway_connection: GatewayConnectionV2 {
gateway_connection: GatewayConnectionV1_1_20 {
gateway_response_timeout: value.gateway_response_timeout,
},
acknowledgements: AcknowledgementsV2 {
acknowledgements: AcknowledgementsV1_1_20 {
average_ack_delay: value.average_ack_delay,
ack_wait_multiplier: value.ack_wait_multiplier,
ack_wait_addition: value.ack_wait_addition,
},
topology: TopologyV2 {
topology: TopologyV1_1_20 {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: false,
},
reply_surbs: ReplySurbsV2 {
reply_surbs: ReplySurbsV1_1_20 {
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,
@@ -166,9 +161,9 @@ impl From<DebugConfigV1> for DebugConfigV2 {
}
}
impl Default for DebugConfigV1 {
impl Default for OldDebugConfigV1_1_13 {
fn default() -> Self {
DebugConfigV1 {
OldDebugConfigV1_1_13 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
@@ -195,10 +190,10 @@ impl Default for DebugConfigV1 {
}
}
impl<T, U> From<ConfigV1<T>> for ConfigV2<U> {
fn from(value: ConfigV1<T>) -> Self {
ConfigV2 {
client: ClientV2 {
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 {
version: value.client.version,
id: value.client.id,
disabled_credentials_mode: value.client.disabled_credentials_mode,
@@ -1,11 +1,12 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v3::{
AcknowledgementsV3, CoverTrafficV3, DebugConfigV3, GatewayConnectionV3,
GatewayEndpointConfigV3, ReplySurbsV3, TopologyV3, TrafficV3,
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 nym_sphinx_params::{PacketSize, PacketType};
use nym_sphinx::params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::path::PathBuf;
@@ -53,41 +54,27 @@ 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 ConfigV2<T> {
pub client: ClientV2<T>,
pub struct ConfigV1_1_20<T> {
pub client: ClientV1_1_20<T>,
#[serde(default)]
pub logging: LoggingV2,
pub logging: LoggingV1_1_20,
#[serde(default)]
pub debug: DebugConfigV2,
pub debug: DebugConfigV1_1_20,
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
pub struct GatewayEndpointConfigV2 {
pub struct GatewayEndpointConfigV1_1_20 {
pub gateway_id: String,
pub gateway_owner: String,
pub gateway_listener: String,
}
impl From<GatewayEndpointConfigV2> for GatewayEndpointConfigV3 {
fn from(value: GatewayEndpointConfigV2) -> Self {
GatewayEndpointConfigV3 {
impl From<GatewayEndpointConfigV1_1_20> for GatewayEndpointConfigV1_1_20_2 {
fn from(value: GatewayEndpointConfigV1_1_20) -> Self {
GatewayEndpointConfigV1_1_20_2 {
gateway_id: value.gateway_id,
gateway_owner: value.gateway_owner,
gateway_listener: value.gateway_listener,
@@ -96,7 +83,7 @@ impl From<GatewayEndpointConfigV2> for GatewayEndpointConfigV3 {
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ClientV2<T> {
pub struct ClientV1_1_20<T> {
pub version: String,
pub id: String,
#[serde(default)]
@@ -111,7 +98,7 @@ pub struct ClientV2<T> {
pub public_encryption_key_file: PathBuf,
pub gateway_shared_key_file: PathBuf,
pub ack_key_file: PathBuf,
pub gateway_endpoint: GatewayEndpointConfigV2,
pub gateway_endpoint: GatewayEndpointConfigV1_1_20,
pub database_path: PathBuf,
#[serde(default)]
pub reply_surb_database_path: PathBuf,
@@ -123,11 +110,11 @@ pub struct ClientV2<T> {
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingV2 {}
pub struct LoggingV1_1_20 {}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct TrafficV2 {
pub struct TrafficV1_1_20 {
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
#[serde(with = "humantime_serde")]
@@ -137,9 +124,9 @@ pub struct TrafficV2 {
pub secondary_packet_size: Option<PacketSize>,
}
impl From<TrafficV2> for TrafficV3 {
fn from(value: TrafficV2) -> Self {
TrafficV3 {
impl From<TrafficV1_1_20> for TrafficV1_1_20_2 {
fn from(value: TrafficV1_1_20) -> Self {
TrafficV1_1_20_2 {
average_packet_delay: value.average_packet_delay,
message_sending_average_delay: value.message_sending_average_delay,
disable_main_poisson_packet_distribution: value
@@ -151,9 +138,9 @@ impl From<TrafficV2> for TrafficV3 {
}
}
impl Default for TrafficV2 {
impl Default for TrafficV1_1_20 {
fn default() -> Self {
TrafficV2 {
TrafficV1_1_20 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -165,16 +152,16 @@ impl Default for TrafficV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV2 {
pub struct CoverTrafficV1_1_20 {
#[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<CoverTrafficV2> for CoverTrafficV3 {
fn from(value: CoverTrafficV2) -> Self {
CoverTrafficV3 {
impl From<CoverTrafficV1_1_20> for CoverTrafficV1_1_20_2 {
fn from(value: CoverTrafficV1_1_20) -> Self {
CoverTrafficV1_1_20_2 {
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,
@@ -182,9 +169,9 @@ impl From<CoverTrafficV2> for CoverTrafficV3 {
}
}
impl Default for CoverTrafficV2 {
impl Default for CoverTrafficV1_1_20 {
fn default() -> Self {
CoverTrafficV2 {
CoverTrafficV1_1_20 {
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,
@@ -194,22 +181,22 @@ impl Default for CoverTrafficV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV2 {
pub struct GatewayConnectionV1_1_20 {
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl From<GatewayConnectionV2> for GatewayConnectionV3 {
fn from(value: GatewayConnectionV2) -> Self {
GatewayConnectionV3 {
impl From<GatewayConnectionV1_1_20> for GatewayConnectionV1_1_20_2 {
fn from(value: GatewayConnectionV1_1_20) -> Self {
GatewayConnectionV1_1_20_2 {
gateway_response_timeout: value.gateway_response_timeout,
}
}
}
impl Default for GatewayConnectionV2 {
impl Default for GatewayConnectionV1_1_20 {
fn default() -> Self {
GatewayConnectionV2 {
GatewayConnectionV1_1_20 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -217,7 +204,7 @@ impl Default for GatewayConnectionV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV2 {
pub struct AcknowledgementsV1_1_20 {
#[serde(with = "humantime_serde")]
pub average_ack_delay: Duration,
pub ack_wait_multiplier: f64,
@@ -225,9 +212,9 @@ pub struct AcknowledgementsV2 {
pub ack_wait_addition: Duration,
}
impl From<AcknowledgementsV2> for AcknowledgementsV3 {
fn from(value: AcknowledgementsV2) -> Self {
AcknowledgementsV3 {
impl From<AcknowledgementsV1_1_20> for AcknowledgementsV1_1_20_2 {
fn from(value: AcknowledgementsV1_1_20) -> Self {
AcknowledgementsV1_1_20_2 {
average_ack_delay: value.average_ack_delay,
ack_wait_multiplier: value.ack_wait_multiplier,
ack_wait_addition: value.ack_wait_addition,
@@ -235,9 +222,9 @@ impl From<AcknowledgementsV2> for AcknowledgementsV3 {
}
}
impl Default for AcknowledgementsV2 {
impl Default for AcknowledgementsV1_1_20 {
fn default() -> Self {
AcknowledgementsV2 {
AcknowledgementsV1_1_20 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -247,7 +234,7 @@ impl Default for AcknowledgementsV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV2 {
pub struct TopologyV1_1_20 {
#[serde(with = "humantime_serde")]
pub topology_refresh_rate: Duration,
#[serde(with = "humantime_serde")]
@@ -255,9 +242,9 @@ pub struct TopologyV2 {
pub disable_refreshing: bool,
}
impl From<TopologyV2> for TopologyV3 {
fn from(value: TopologyV2) -> Self {
TopologyV3 {
impl From<TopologyV1_1_20> for TopologyV1_1_20_2 {
fn from(value: TopologyV1_1_20) -> Self {
TopologyV1_1_20_2 {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: value.disable_refreshing,
@@ -265,9 +252,9 @@ impl From<TopologyV2> for TopologyV3 {
}
}
impl Default for TopologyV2 {
impl Default for TopologyV1_1_20 {
fn default() -> Self {
TopologyV2 {
TopologyV1_1_20 {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
@@ -277,7 +264,7 @@ impl Default for TopologyV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV2 {
pub struct ReplySurbsV1_1_20 {
pub minimum_reply_surb_storage_threshold: usize,
pub maximum_reply_surb_storage_threshold: usize,
pub minimum_reply_surb_request_size: u32,
@@ -293,9 +280,9 @@ pub struct ReplySurbsV2 {
pub maximum_reply_key_age: Duration,
}
impl From<ReplySurbsV2> for ReplySurbsV3 {
fn from(value: ReplySurbsV2) -> Self {
ReplySurbsV3 {
impl From<ReplySurbsV1_1_20> for ReplySurbsV1_1_20_2 {
fn from(value: ReplySurbsV1_1_20) -> Self {
ReplySurbsV1_1_20_2 {
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,
@@ -310,9 +297,9 @@ impl From<ReplySurbsV2> for ReplySurbsV3 {
}
}
impl Default for ReplySurbsV2 {
impl Default for ReplySurbsV1_1_20 {
fn default() -> Self {
ReplySurbsV2 {
ReplySurbsV1_1_20 {
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,
@@ -329,18 +316,18 @@ impl Default for ReplySurbsV2 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV2 {
pub traffic: TrafficV2,
pub cover_traffic: CoverTrafficV2,
pub gateway_connection: GatewayConnectionV2,
pub acknowledgements: AcknowledgementsV2,
pub topology: TopologyV2,
pub reply_surbs: ReplySurbsV2,
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,
}
impl From<DebugConfigV2> for DebugConfigV3 {
fn from(value: DebugConfigV2) -> Self {
DebugConfigV3 {
impl From<DebugConfigV1_1_20> for DebugConfigV1_1_20_2 {
fn from(value: DebugConfigV1_1_20) -> Self {
DebugConfigV1_1_20_2 {
traffic: value.traffic.into(),
cover_traffic: value.cover_traffic.into(),
gateway_connection: value.gateway_connection.into(),
@@ -1,12 +1,12 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v4::{
AcknowledgementsV4, ClientV4, ConfigV4, CoverTrafficV4, DebugConfigV4, GatewayConnectionV4,
ReplySurbsV4, TopologyV4, TrafficV4,
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::v5::GatewayEndpointConfigV5;
use nym_sphinx_params::{PacketSize, PacketType};
use crate::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33;
use nym_sphinx::params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -50,31 +50,18 @@ 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 ConfigV3 {
pub client: ClientV3,
pub struct ConfigV1_1_20_2 {
pub client: ClientV1_1_20_2,
#[serde(default)]
pub debug: DebugConfigV3,
pub debug: DebugConfigV1_1_20_2,
}
impl From<ConfigV3> for ConfigV4 {
fn from(value: ConfigV3) -> Self {
ConfigV4 {
impl From<ConfigV1_1_20_2> for ConfigV1_1_30 {
fn from(value: ConfigV1_1_20_2) -> Self {
ConfigV1_1_30 {
client: value.client.into(),
debug: value.debug.into(),
}
@@ -82,7 +69,7 @@ impl From<ConfigV3> for ConfigV4 {
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
pub struct GatewayEndpointConfigV3 {
pub struct GatewayEndpointConfigV1_1_20_2 {
/// 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,
@@ -94,9 +81,9 @@ pub struct GatewayEndpointConfigV3 {
pub gateway_listener: String,
}
impl From<GatewayEndpointConfigV3> for GatewayEndpointConfigV5 {
fn from(value: GatewayEndpointConfigV3) -> Self {
GatewayEndpointConfigV5 {
impl From<GatewayEndpointConfigV1_1_20_2> for OldGatewayEndpointConfigV1_1_33 {
fn from(value: GatewayEndpointConfigV1_1_20_2) -> Self {
OldGatewayEndpointConfigV1_1_33 {
gateway_id: value.gateway_id,
gateway_owner: value.gateway_owner,
gateway_listener: value.gateway_listener,
@@ -105,7 +92,7 @@ impl From<GatewayEndpointConfigV3> for GatewayEndpointConfigV5 {
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ClientV3 {
pub struct ClientV1_1_20_2 {
pub version: String,
pub id: String,
@@ -118,12 +105,12 @@ pub struct ClientV3 {
#[serde(alias = "validator_api_urls")]
pub nym_api_urls: Vec<Url>,
pub gateway_endpoint: GatewayEndpointConfigV3,
pub gateway_endpoint: GatewayEndpointConfigV1_1_20_2,
}
impl From<ClientV3> for ClientV4 {
fn from(value: ClientV3) -> Self {
ClientV4 {
impl From<ClientV1_1_20_2> for ClientV1_1_30 {
fn from(value: ClientV1_1_20_2) -> Self {
ClientV1_1_30 {
version: value.version,
id: value.id,
disabled_credentials_mode: value.disabled_credentials_mode,
@@ -135,7 +122,7 @@ impl From<ClientV3> for ClientV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct TrafficV3 {
pub struct TrafficV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
#[serde(with = "humantime_serde")]
@@ -146,9 +133,9 @@ pub struct TrafficV3 {
pub packet_type: PacketType,
}
impl From<TrafficV3> for TrafficV4 {
fn from(value: TrafficV3) -> Self {
TrafficV4 {
impl From<TrafficV1_1_20_2> for TrafficV1_1_30 {
fn from(value: TrafficV1_1_20_2) -> Self {
TrafficV1_1_30 {
average_packet_delay: value.average_packet_delay,
message_sending_average_delay: value.message_sending_average_delay,
disable_main_poisson_packet_distribution: value
@@ -160,9 +147,9 @@ impl From<TrafficV3> for TrafficV4 {
}
}
impl Default for TrafficV3 {
impl Default for TrafficV1_1_20_2 {
fn default() -> Self {
TrafficV3 {
TrafficV1_1_20_2 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -175,16 +162,16 @@ impl Default for TrafficV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV3 {
pub struct CoverTrafficV1_1_20_2 {
#[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<CoverTrafficV3> for CoverTrafficV4 {
fn from(value: CoverTrafficV3) -> Self {
CoverTrafficV4 {
impl From<CoverTrafficV1_1_20_2> for CoverTrafficV1_1_30 {
fn from(value: CoverTrafficV1_1_20_2) -> Self {
CoverTrafficV1_1_30 {
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,
@@ -192,9 +179,9 @@ impl From<CoverTrafficV3> for CoverTrafficV4 {
}
}
impl Default for CoverTrafficV3 {
impl Default for CoverTrafficV1_1_20_2 {
fn default() -> Self {
CoverTrafficV3 {
CoverTrafficV1_1_20_2 {
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,
@@ -204,22 +191,22 @@ impl Default for CoverTrafficV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV3 {
pub struct GatewayConnectionV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl From<GatewayConnectionV3> for GatewayConnectionV4 {
fn from(value: GatewayConnectionV3) -> Self {
GatewayConnectionV4 {
impl From<GatewayConnectionV1_1_20_2> for GatewayConnectionV1_1_30 {
fn from(value: GatewayConnectionV1_1_20_2) -> Self {
GatewayConnectionV1_1_30 {
gateway_response_timeout: value.gateway_response_timeout,
}
}
}
impl Default for GatewayConnectionV3 {
impl Default for GatewayConnectionV1_1_20_2 {
fn default() -> Self {
GatewayConnectionV3 {
GatewayConnectionV1_1_20_2 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -227,7 +214,7 @@ impl Default for GatewayConnectionV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV3 {
pub struct AcknowledgementsV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub average_ack_delay: Duration,
pub ack_wait_multiplier: f64,
@@ -235,9 +222,9 @@ pub struct AcknowledgementsV3 {
pub ack_wait_addition: Duration,
}
impl From<AcknowledgementsV3> for AcknowledgementsV4 {
fn from(value: AcknowledgementsV3) -> Self {
AcknowledgementsV4 {
impl From<AcknowledgementsV1_1_20_2> for AcknowledgementsV1_1_30 {
fn from(value: AcknowledgementsV1_1_20_2) -> Self {
AcknowledgementsV1_1_30 {
average_ack_delay: value.average_ack_delay,
ack_wait_multiplier: value.ack_wait_multiplier,
ack_wait_addition: value.ack_wait_addition,
@@ -245,9 +232,9 @@ impl From<AcknowledgementsV3> for AcknowledgementsV4 {
}
}
impl Default for AcknowledgementsV3 {
impl Default for AcknowledgementsV1_1_20_2 {
fn default() -> Self {
AcknowledgementsV3 {
AcknowledgementsV1_1_20_2 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -257,7 +244,7 @@ impl Default for AcknowledgementsV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV3 {
pub struct TopologyV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub topology_refresh_rate: Duration,
#[serde(with = "humantime_serde")]
@@ -265,9 +252,9 @@ pub struct TopologyV3 {
pub disable_refreshing: bool,
}
impl Default for TopologyV3 {
impl Default for TopologyV1_1_20_2 {
fn default() -> Self {
TopologyV3 {
TopologyV1_1_20_2 {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
@@ -275,9 +262,9 @@ impl Default for TopologyV3 {
}
}
impl From<TopologyV3> for TopologyV4 {
fn from(value: TopologyV3) -> Self {
TopologyV4 {
impl From<TopologyV1_1_20_2> for TopologyV1_1_30 {
fn from(value: TopologyV1_1_20_2) -> Self {
TopologyV1_1_30 {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: value.disable_refreshing,
@@ -288,7 +275,7 @@ impl From<TopologyV3> for TopologyV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV3 {
pub struct ReplySurbsV1_1_20_2 {
pub minimum_reply_surb_storage_threshold: usize,
pub maximum_reply_surb_storage_threshold: usize,
pub minimum_reply_surb_request_size: u32,
@@ -304,9 +291,9 @@ pub struct ReplySurbsV3 {
pub maximum_reply_key_age: Duration,
}
impl Default for ReplySurbsV3 {
impl Default for ReplySurbsV1_1_20_2 {
fn default() -> Self {
ReplySurbsV3 {
ReplySurbsV1_1_20_2 {
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,
@@ -321,9 +308,9 @@ impl Default for ReplySurbsV3 {
}
}
impl From<ReplySurbsV3> for ReplySurbsV4 {
fn from(value: ReplySurbsV3) -> Self {
ReplySurbsV4 {
impl From<ReplySurbsV1_1_20_2> for ReplySurbsV1_1_30 {
fn from(value: ReplySurbsV1_1_20_2) -> Self {
ReplySurbsV1_1_30 {
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,
@@ -340,18 +327,18 @@ impl From<ReplySurbsV3> for ReplySurbsV4 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV3 {
pub traffic: TrafficV3,
pub cover_traffic: CoverTrafficV3,
pub gateway_connection: GatewayConnectionV3,
pub acknowledgements: AcknowledgementsV3,
pub topology: TopologyV3,
pub reply_surbs: ReplySurbsV3,
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,
}
impl From<DebugConfigV3> for DebugConfigV4 {
fn from(value: DebugConfigV3) -> Self {
DebugConfigV4 {
impl From<DebugConfigV1_1_20_2> for DebugConfigV1_1_30 {
fn from(value: DebugConfigV1_1_20_2) -> Self {
DebugConfigV1_1_30 {
traffic: value.traffic.into(),
cover_traffic: value.cover_traffic.into(),
gateway_connection: value.gateway_connection.into(),
@@ -1,13 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v5::{
AcknowledgementsV5, ClientV5, ConfigV5, CoverTrafficV5, DebugConfigV5, GatewayConnectionV5,
GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
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::CountryGroup;
use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -53,39 +56,27 @@ 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 ConfigV4 {
pub client: ClientV4,
pub struct ConfigV1_1_30 {
pub client: ClientV1_1_30,
#[serde(default)]
pub debug: DebugConfigV4,
pub debug: DebugConfigV1_1_30,
}
impl From<ConfigV4> for ConfigV5 {
fn from(value: ConfigV4) -> Self {
ConfigV5 {
client: ClientV5 {
impl From<ConfigV1_1_30> for ConfigV1_1_33 {
fn from(value: ConfigV1_1_30) -> Self {
ConfigV1_1_33 {
client: ClientV1_1_33 {
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: DebugConfigV5 {
traffic: TrafficV5 {
debug: DebugConfigV1_1_33 {
traffic: TrafficV1_1_33 {
average_packet_delay: value.debug.traffic.average_packet_delay,
message_sending_average_delay: value
.debug
@@ -99,7 +90,7 @@ impl From<ConfigV4> for ConfigV5 {
secondary_packet_size: value.debug.traffic.secondary_packet_size,
packet_type: value.debug.traffic.packet_type,
},
cover_traffic: CoverTrafficV5 {
cover_traffic: CoverTrafficV1_1_33 {
loop_cover_traffic_average_delay: value
.debug
.cover_traffic
@@ -113,18 +104,18 @@ impl From<ConfigV4> for ConfigV5 {
.cover_traffic
.disable_loop_cover_traffic_stream,
},
gateway_connection: GatewayConnectionV5 {
gateway_connection: GatewayConnectionV1_1_33 {
gateway_response_timeout: value
.debug
.gateway_connection
.gateway_response_timeout,
},
acknowledgements: AcknowledgementsV5 {
acknowledgements: AcknowledgementsV1_1_33 {
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: TopologyV5 {
topology: TopologyV1_1_33 {
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,
@@ -134,7 +125,7 @@ impl From<ConfigV4> for ConfigV5 {
.max_startup_gateway_waiting_period,
topology_structure: value.debug.topology.topology_structure.into(),
},
reply_surbs: ReplySurbsV5 {
reply_surbs: ReplySurbsV1_1_33 {
minimum_reply_surb_storage_threshold: value
.debug
.reply_surbs
@@ -178,7 +169,7 @@ impl From<ConfigV4> for ConfigV5 {
#[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 ClientV4 {
pub struct ClientV1_1_30 {
/// Version of the client for which this configuration was created.
pub version: String,
@@ -202,7 +193,7 @@ pub struct ClientV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TrafficV4 {
pub struct TrafficV1_1_30 {
/// 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 +224,9 @@ pub struct TrafficV4 {
pub packet_type: PacketType,
}
impl Default for TrafficV4 {
impl Default for TrafficV1_1_30 {
fn default() -> Self {
TrafficV4 {
TrafficV1_1_30 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -248,7 +239,7 @@ impl Default for TrafficV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV4 {
pub struct CoverTrafficV1_1_30 {
/// 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 +254,9 @@ pub struct CoverTrafficV4 {
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTrafficV4 {
impl Default for CoverTrafficV1_1_30 {
fn default() -> Self {
CoverTrafficV4 {
CoverTrafficV1_1_30 {
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 +266,16 @@ impl Default for CoverTrafficV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV4 {
pub struct GatewayConnectionV1_1_30 {
/// 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 GatewayConnectionV4 {
impl Default for GatewayConnectionV1_1_30 {
fn default() -> Self {
GatewayConnectionV4 {
GatewayConnectionV1_1_30 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -292,7 +283,7 @@ impl Default for GatewayConnectionV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV4 {
pub struct AcknowledgementsV1_1_30 {
/// 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 +303,9 @@ pub struct AcknowledgementsV4 {
pub ack_wait_addition: Duration,
}
impl Default for AcknowledgementsV4 {
impl Default for AcknowledgementsV1_1_30 {
fn default() -> Self {
AcknowledgementsV4 {
AcknowledgementsV1_1_30 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -324,7 +315,7 @@ impl Default for AcknowledgementsV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV4 {
pub struct TopologyV1_1_30 {
/// 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,23 +338,23 @@ pub struct TopologyV4 {
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructureV4,
pub topology_structure: TopologyStructureV1_1_30,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructureV4 {
pub enum TopologyStructureV1_1_30 {
#[default]
NymApi,
GeoAware(GroupByV4),
GeoAware(GroupByV1_1_30),
}
impl From<TopologyStructureV4> for TopologyStructureV5 {
fn from(value: TopologyStructureV4) -> Self {
impl From<TopologyStructureV1_1_30> for TopologyStructureV1_1_33 {
fn from(value: TopologyStructureV1_1_30) -> Self {
match value {
TopologyStructureV4::NymApi => TopologyStructureV5::NymApi,
TopologyStructureV4::GeoAware(group_by) => {
TopologyStructureV5::GeoAware(group_by.into())
TopologyStructureV1_1_30::NymApi => TopologyStructureV1_1_33::NymApi,
TopologyStructureV1_1_30::GeoAware(group_by) => {
TopologyStructureV1_1_33::GeoAware(group_by.into())
}
}
}
@@ -371,44 +362,44 @@ impl From<TopologyStructureV4> for TopologyStructureV5 {
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupByV4 {
pub enum GroupByV1_1_30 {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl From<GroupByV4> for GroupByV5 {
fn from(value: GroupByV4) -> Self {
impl From<GroupByV1_1_30> for GroupByV1_1_33 {
fn from(value: GroupByV1_1_30) -> Self {
match value {
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country),
GroupByV4::NymAddress(addr) => GroupByV5::NymAddress(addr),
GroupByV1_1_30::CountryGroup(country) => GroupByV1_1_33::CountryGroup(country),
GroupByV1_1_30::NymAddress(addr) => GroupByV1_1_33::NymAddress(addr),
}
}
}
impl std::fmt::Display for GroupByV4 {
impl std::fmt::Display for GroupByV1_1_30 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupByV4::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV4::NymAddress(address) => write!(f, "address: {}", address),
GroupByV1_1_30::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV1_1_30::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for TopologyV4 {
impl Default for TopologyV1_1_30 {
fn default() -> Self {
TopologyV4 {
TopologyV1_1_30 {
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: TopologyStructureV4::default(),
topology_structure: TopologyStructureV1_1_30::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV4 {
pub struct ReplySurbsV1_1_30 {
/// 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,
@@ -446,9 +437,9 @@ pub struct ReplySurbsV4 {
pub maximum_reply_key_age: Duration,
}
impl Default for ReplySurbsV4 {
impl Default for ReplySurbsV1_1_30 {
fn default() -> Self {
ReplySurbsV4 {
ReplySurbsV1_1_30 {
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,
@@ -465,22 +456,22 @@ impl Default for ReplySurbsV4 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV4 {
pub struct DebugConfigV1_1_30 {
/// Defines all configuration options related to traffic streams.
pub traffic: TrafficV4,
pub traffic: TrafficV1_1_30,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTrafficV4,
pub cover_traffic: CoverTrafficV1_1_30,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnectionV4,
pub gateway_connection: GatewayConnectionV1_1_30,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: AcknowledgementsV4,
pub acknowledgements: AcknowledgementsV1_1_30,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: TopologyV4,
pub topology: TopologyV1_1_30,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbsV4,
pub reply_surbs: ReplySurbsV1_1_30,
}
@@ -1,12 +1,15 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{
Acknowledgements, Client, Config, CountryGroup, CoverTraffic, DebugConfig, GatewayConnection,
GroupBy, ReplySurbs, Topology, TopologyStructure, Traffic,
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 nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -52,21 +55,8 @@ 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 GatewayEndpointConfigV5 {
pub struct OldGatewayEndpointConfigV1_1_33 {
/// 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,
@@ -80,15 +70,15 @@ pub struct GatewayEndpointConfigV5 {
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV5 {
pub client: ClientV5,
pub struct ConfigV1_1_33 {
pub client: ClientV1_1_33,
#[serde(default)]
pub debug: DebugConfigV5,
pub debug: DebugConfigV1_1_33,
}
impl From<ConfigV5> for Config {
fn from(value: ConfigV5) -> Self {
impl From<ConfigV1_1_33> for Config {
fn from(value: ConfigV1_1_33) -> Self {
Config {
client: Client {
version: value.client.version,
@@ -188,7 +178,7 @@ impl From<ConfigV5> 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 ClientV5 {
pub struct ClientV1_1_33 {
/// Version of the client for which this configuration was created.
pub version: String,
@@ -212,7 +202,7 @@ pub struct ClientV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TrafficV5 {
pub struct TrafficV1_1_33 {
/// 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
@@ -243,9 +233,9 @@ pub struct TrafficV5 {
pub packet_type: PacketType,
}
impl Default for TrafficV5 {
impl Default for TrafficV1_1_33 {
fn default() -> Self {
TrafficV5 {
TrafficV1_1_33 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -258,7 +248,7 @@ impl Default for TrafficV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV5 {
pub struct CoverTrafficV1_1_33 {
/// 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")]
@@ -273,9 +263,9 @@ pub struct CoverTrafficV5 {
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTrafficV5 {
impl Default for CoverTrafficV1_1_33 {
fn default() -> Self {
CoverTrafficV5 {
CoverTrafficV1_1_33 {
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,
@@ -285,16 +275,16 @@ impl Default for CoverTrafficV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV5 {
pub struct GatewayConnectionV1_1_33 {
/// 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 GatewayConnectionV5 {
impl Default for GatewayConnectionV1_1_33 {
fn default() -> Self {
GatewayConnectionV5 {
GatewayConnectionV1_1_33 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -302,7 +292,7 @@ impl Default for GatewayConnectionV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV5 {
pub struct AcknowledgementsV1_1_33 {
/// 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
@@ -322,9 +312,9 @@ pub struct AcknowledgementsV5 {
pub ack_wait_addition: Duration,
}
impl Default for AcknowledgementsV5 {
impl Default for AcknowledgementsV1_1_33 {
fn default() -> Self {
AcknowledgementsV5 {
AcknowledgementsV1_1_33 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -334,7 +324,7 @@ impl Default for AcknowledgementsV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV5 {
pub struct TopologyV1_1_33 {
/// 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")]
@@ -357,66 +347,68 @@ pub struct TopologyV5 {
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructureV5,
pub topology_structure: TopologyStructureV1_1_33,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructureV5 {
pub enum TopologyStructureV1_1_33 {
#[default]
NymApi,
GeoAware(GroupByV5),
GeoAware(GroupByV1_1_33),
}
impl From<TopologyStructureV5> for TopologyStructure {
fn from(value: TopologyStructureV5) -> Self {
impl From<TopologyStructureV1_1_33> for TopologyStructure {
fn from(value: TopologyStructureV1_1_33) -> Self {
match value {
TopologyStructureV5::NymApi => TopologyStructure::NymApi,
TopologyStructureV5::GeoAware(group_by) => TopologyStructure::GeoAware(group_by.into()),
TopologyStructureV1_1_33::NymApi => TopologyStructure::NymApi,
TopologyStructureV1_1_33::GeoAware(group_by) => {
TopologyStructure::GeoAware(group_by.into())
}
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupByV5 {
pub enum GroupByV1_1_33 {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl From<GroupByV5> for GroupBy {
fn from(value: GroupByV5) -> Self {
impl From<GroupByV1_1_33> for GroupBy {
fn from(value: GroupByV1_1_33) -> Self {
match value {
GroupByV5::CountryGroup(country) => GroupBy::CountryGroup(country),
GroupByV5::NymAddress(addr) => GroupBy::NymAddress(addr),
GroupByV1_1_33::CountryGroup(country) => GroupBy::CountryGroup(country),
GroupByV1_1_33::NymAddress(addr) => GroupBy::NymAddress(addr),
}
}
}
impl std::fmt::Display for GroupByV5 {
impl std::fmt::Display for GroupByV1_1_33 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupByV5::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV5::NymAddress(address) => write!(f, "address: {}", address),
GroupByV1_1_33::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV1_1_33::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for TopologyV5 {
impl Default for TopologyV1_1_33 {
fn default() -> Self {
TopologyV5 {
TopologyV1_1_33 {
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: TopologyStructureV5::default(),
topology_structure: TopologyStructureV1_1_33::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV5 {
pub struct ReplySurbsV1_1_33 {
/// 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,
@@ -458,9 +450,9 @@ pub struct ReplySurbsV5 {
pub surb_mix_hops: Option<u8>,
}
impl Default for ReplySurbsV5 {
impl Default for ReplySurbsV1_1_33 {
fn default() -> Self {
ReplySurbsV5 {
ReplySurbsV1_1_33 {
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,
@@ -478,22 +470,22 @@ impl Default for ReplySurbsV5 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV5 {
pub struct DebugConfigV1_1_33 {
/// Defines all configuration options related to traffic streams.
pub traffic: TrafficV5,
pub traffic: TrafficV1_1_33,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTrafficV5,
pub cover_traffic: CoverTrafficV1_1_33,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnectionV5,
pub gateway_connection: GatewayConnectionV1_1_33,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: AcknowledgementsV5,
pub acknowledgements: AcknowledgementsV1_1_33,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: TopologyV5,
pub topology: TopologyV1_1_33,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbsV5,
pub reply_surbs: ReplySurbsV1_1_33,
}
+3 -3
View File
@@ -201,7 +201,7 @@ where
log::debug!("Setting up gateway");
match setup {
GatewaySetup::MustLoad { gateway_id } => {
log::debug!("GatewaySetup::MustLoad with id: {gateway_id:?}");
log::trace!("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::debug!("GatewaySetup::New with spec: {specification:?}");
log::trace!("GatewaySetup::New with spec: {specification:?}");
setup_new_gateway(
key_store,
details_store,
@@ -224,7 +224,7 @@ where
gateway_details,
client_keys: managed_keys,
} => {
log::debug!("GatewaySetup::ReuseConnection");
log::trace!("GatewaySetup::ReuseConnection");
Ok(reuse_gateway_connection(
authenticated_ephemeral_client,
*gateway_details,
@@ -16,8 +16,6 @@ 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" }
@@ -79,7 +79,6 @@ 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,
@@ -850,7 +849,6 @@ 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> {
@@ -10,14 +10,9 @@ 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)]
@@ -53,22 +48,6 @@ 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<()>),
@@ -76,10 +55,7 @@ pub(crate) struct PartiallyDelegated {
}
impl PartiallyDelegated {
fn recover_received_plaintexts(
ws_msgs: Vec<Message>,
shared_key: &SharedKeys,
) -> Result<Vec<Vec<u8>>, GatewayClientError> {
fn recover_received_plaintexts(ws_msgs: Vec<Message>, shared_key: &SharedKeys) -> Vec<Vec<u8>> {
let mut plaintexts = Vec::with_capacity(ws_msgs.len());
for ws_msg in ws_msgs {
match ws_msg {
@@ -97,32 +73,15 @@ 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,
}
}
Ok(plaintexts)
plaintexts
}
fn route_socket_messages(
@@ -130,7 +89,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)
}
@@ -170,8 +129,7 @@ impl PartiallyDelegated {
};
if let Err(err) = Self::route_socket_messages(ws_msgs, &packet_router, shared_key.as_ref()) {
log::error!("Route socket messages failed: {err}");
break Err(err)
log::warn!("Route socket messages failed: {err}");
}
}
};
@@ -263,7 +221,6 @@ 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),
+1 -1
View File
@@ -17,7 +17,7 @@ csv = "1.3.0"
cw-utils = { workspace = true }
futures = { workspace = true }
handlebars = "3.0.1"
humantime-serde = { workspace = true }
humantime-serde = "1.0"
inquire = "0.6.2"
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
log = { workspace = true }
@@ -148,10 +148,6 @@ 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?;
@@ -1,354 +0,0 @@
// 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.get(&mix_id.to_string()).is_some()
{
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,7 +6,6 @@ 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;
@@ -27,8 +26,6 @@ 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
-15
View File
@@ -1,15 +0,0 @@
[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
-158
View File
@@ -1,158 +0,0 @@
// 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,
}
}
}
@@ -1,48 +0,0 @@
/*
* 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" AND coconut_credentials.expired = false
WHERE coconut_credentials.credential_type == "FreeBandwidthPass"
AND NOT EXISTS (SELECT 1
FROM credential_usage
WHERE credential_usage.credential_id = coconut_credentials.id
@@ -1,8 +1,6 @@
// 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};
@@ -25,12 +23,6 @@ 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;
@@ -10,9 +10,6 @@ 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};
@@ -1,18 +0,0 @@
// 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
View File
@@ -3,6 +3,3 @@
pub mod encryption;
pub mod identity;
pub use encryption as x25519;
pub use identity as ed25519;
+1 -1
View File
@@ -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);
-20
View File
@@ -1,20 +0,0 @@
[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 }
+3 -5
View File
@@ -10,11 +10,11 @@ license.workspace = true
[dependencies]
bytes = "1.0"
futures = { workspace = true }
humantime-serde = { workspace = true }
humantime-serde = "1.0"
log = { workspace = true }
rand = "0.8"
serde = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = [
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.24.1", features = [
"time",
"macros",
"rt",
@@ -23,7 +23,6 @@ tokio = { workspace = true, features = [
] }
tokio-util = { workspace = true, features = ["codec"] }
url = { workspace = true }
time.workspace = true
thiserror = { workspace = true }
nym-crypto = { path = "../crypto" }
@@ -38,4 +37,3 @@ 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" }
+245 -21
View File
@@ -1,35 +1,259 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_node_http_api::state::metrics::{SharedVerlocStats, VerlocNodeResult};
use std::mem;
use time::OffsetDateTime;
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;
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(Clone, Default)]
pub struct AtomicVerlocResult {
inner: Arc<RwLock<VerlocResult>>,
}
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;
#[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(),
})),
}
}
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);
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);
// 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.current_run_data.results.sort()
write_permit.results.sort()
}
async fn finish_measurements(&self) {
self.write().await.current_run_data.run_finished = Some(OffsetDateTime::now_utc())
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);
}
}
+18 -19
View File
@@ -1,4 +1,4 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::verloc::listener::PacketListener;
@@ -9,7 +9,6 @@ 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;
@@ -21,9 +20,7 @@ use tokio::task::JoinHandle;
use tokio::time::sleep;
use url::Url;
use measurement::VerlocStatsUpdateExt;
// pub use crate::verloc::measurement::{AtomicVerlocResult, Verloc, VerlocResult};
pub use crate::verloc::measurement::{AtomicVerlocResult, Verloc, VerlocResult};
pub mod error;
pub(crate) mod listener;
@@ -182,7 +179,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,
state: SharedVerlocStats,
results: AtomicVerlocResult,
}
impl VerlocMeasurer {
@@ -213,14 +210,10 @@ impl VerlocMeasurer {
config.nym_api_urls[0].clone(),
),
config,
state: SharedVerlocStats::default(),
results: AtomicVerlocResult::new(),
}
}
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");
@@ -232,6 +225,10 @@ 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())
@@ -273,7 +270,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
};
@@ -281,16 +278,18 @@ 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 {identity}: {err}");
debug!(
"Failed to perform measurement for {} - {}",
execution_result.1.to_base58_string(),
err
);
None
}
Ok(result) => Some(result),
};
chunk_results.push(VerlocNodeResult::new(identity, measurement_result));
chunk_results.push(Verloc::new(execution_result.1, measurement_result));
},
_ = shutdown_listener.recv() => {
trace!("Shutdown received while measuring");
@@ -300,7 +299,7 @@ impl VerlocMeasurer {
}
// update the results vector with chunks as they become available (by default every 50 nodes)
self.state.append_measurement_results(chunk_results).await;
self.results.append_results(chunk_results).await;
}
MeasurementOutcome::Done
@@ -359,7 +358,7 @@ impl VerlocMeasurer {
.collect::<Vec<_>>();
// on start of each run remove old results
self.state.start_new_measurements(tested_nodes.len()).await;
self.results.reset_results(tested_nodes.len()).await;
if let MeasurementOutcome::Shutdown = self.perform_measurement(tested_nodes).await {
log::trace!("Shutting down after aborting measurements");
@@ -367,7 +366,7 @@ impl VerlocMeasurer {
}
// write current time to "run finished" field
self.state.finish_measurements().await;
self.results.finish_measurements().await;
info!(
"Finished performing verloc measurements. The next one will happen in {:?}",
+4 -4
View File
@@ -1,11 +1,11 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021 - 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<VerlocMeasurement, RttError> {
) -> Result<Measurement, 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(VerlocMeasurement::new(&results))
Ok(Measurement::new(&results))
}
}
-3
View File
@@ -3,6 +3,3 @@
pub mod clients;
pub mod nodes;
pub use clients::Recipient;
pub use nodes::NodeIdentity;
+1 -5
View File
@@ -348,7 +348,7 @@ impl TaskClient {
"unnamed-TaskClient".to_string()
};
log!(target: target, level, "{}", format!("[{target}] {msg}"))
log!(target: target, level, "{msg}")
}
#[must_use]
@@ -474,10 +474,6 @@ 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;
-7
View File
@@ -6,7 +6,6 @@ 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};
@@ -78,12 +77,6 @@ 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;
-13
View File
@@ -1,13 +0,0 @@
[package]
name = "autodoc"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
env_logger = "0.11.3"
log.workspace = true
-4
View File
@@ -1,4 +0,0 @@
# `autodoc`
Command output documentation generator WIP
@@ -1,88 +0,0 @@
# `nym-api` Binary Commands
These docs are autogenerated by the `autodocs` script.
**TODO add link**
```
Starting nym api...
Usage: nym-api [OPTIONS] <COMMAND>
Commands:
init Initialise a Nym Api instance with persistent config.toml file
run Run the Nym Api with provided configuration optionally overriding set parameters
build-info Show build information of this binary
help Print this message or the help of the given subcommand(s)
Options:
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file that configures the Nym API
-h, --help Print help
-V, --version Print version
```
### `init`
```
Starting nym api...
Initialise a Nym Api instance with persistent config.toml file
Usage: nym-api init [OPTIONS]
Options:
--id <ID>
Id of the nym-api we want to initialise. if unspecified, a default value will be used. default: "default" [default: default]
-m, --enable-monitor
Specifies whether network monitoring is enabled on this API default: false
-r, --enable-rewarding
Specifies whether network rewarding is enabled on this API default: false
--nyxd-validator <NYXD_VALIDATOR>
Endpoint to nyxd instance used for contract information. default: http://localhost:26657
--mnemonic <MNEMONIC>
Mnemonic of the network monitor used for sending rewarding and zk-nyms transactions default: None
--enable-zk-nym
Flag to indicate whether credential signer authority is enabled on this API default: false
--announce-address <ANNOUNCE_ADDRESS>
Announced address that is going to be put in the DKG contract where zk-nym clients will connect to obtain their credentials default: None
--monitor-credentials-mode
Set this nym api to work in a enabled credentials that would attempt to use gateway with the bandwidth credential requirement
-h, --help
Print help
```
### `run`
```
Starting nym api...
Run the Nym Api with provided configuration optionally overriding set parameters
Usage: nym-api run [OPTIONS]
Options:
--id <ID>
Id of the nym-api we want to run.if unspecified, a default value will be used. default: "default" [default: default]
-m, --enable-monitor <ENABLE_MONITOR>
Specifies whether network monitoring is enabled on this API default: None - config value will be used instead [possible values: true, false]
-r, --enable-rewarding <ENABLE_REWARDING>
Specifies whether network rewarding is enabled on this API default: None - config value will be used instead [possible values: true, false]
--nyxd-validator <NYXD_VALIDATOR>
Endpoint to nyxd instance used for contract information. default: None - config value will be used instead
--mnemonic <MNEMONIC>
Mnemonic of the network monitor used for sending rewarding and zk-nyms transactions default: None - config value will be used instead
--enable-zk-nym <ENABLE_ZK_NYM>
Flag to indicate whether coconut signer authority is enabled on this API default: None - config value will be used instead [possible values: true, false]
--announce-address <ANNOUNCE_ADDRESS>
Announced address that is going to be put in the DKG contract where zk-nym clients will connect to obtain their credentials default: None - config value will be used instead
--monitor-credentials-mode <MONITOR_CREDENTIALS_MODE>
Set this nym api to work in a enabled credentials that would attempt to use gateway with the bandwidth credential requirement default: None - config value will be used instead [possible values: true, false]
-h, --help
Print help
```
### `build-info`
```
Starting nym api...
Show build information of this binary
Usage: nym-api build-info [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
File diff suppressed because it is too large Load Diff
@@ -1,721 +0,0 @@
# `nym-client` Binary Commands
These docs are autogenerated by the `autodocs` script.
**TODO add link**
```
Implementation of the Nym Client
Usage: nym-client [OPTIONS] <COMMAND>
Commands:
init Initialise a Nym client. Do this first!
run Run the Nym client with provided configuration client optionally overriding set parameters
import-credential Import a pre-generated credential
list-gateways List all registered with gateways
add-gateway Add new gateway to this client
switch-gateway Change the currently active gateway. Note that you must have already registered with the new gateway!
build-info Show build information of this binary
completions Generate shell completions
generate-fig-spec Generate Fig specification
help Print this message or the help of the given subcommand(s)
Options:
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file that configures the client
--no-banner Flag used for disabling the printed banner in tty
-h, --help Print help
-V, --version Print version
```
### `init`
```
Initialise a Nym client. Do this first!
Usage: nym-client init [OPTIONS] --id <ID>
Options:
--id <ID>
Id of client we want to create config for
--gateway <GATEWAY>
Id of the gateway we are going to connect to
--force-tls-gateway
Specifies whether the client will attempt to enforce tls connection to the desired gateway
--latency-based-selection
Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly
--nym-apis <NYM_APIS>
Comma separated list of rest endpoints of the API validators
--disable-socket <DISABLE_SOCKET>
Whether to not start the websocket [possible values: true, false]
-p, --port <PORT>
Port for the socket (if applicable) to listen on in all subsequent runs
--host <HOST>
Ip for the socket (if applicable) to listen for requests
-o, --output <OUTPUT>
[default: text] [possible values: text, json]
-h, --help
Print help
```
### `run`
```
Run the Nym client with provided configuration client optionally overriding set parameters
Usage: nym-client run [OPTIONS] --id <ID>
Options:
--id <ID>
Id of client we want to create config for
--gateway <GATEWAY>
Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened
--nym-apis <NYM_APIS>
Comma separated list of rest endpoints of the API validators
--disable-socket <DISABLE_SOCKET>
Whether to not start the websocket [possible values: true, false]
-p, --port <PORT>
Port for the socket to listen on
--host <HOST>
Ip for the socket (if applicable) to listen for requests
-h, --help
Print help
```
### `import-credential`
```
Import a pre-generated credential
Usage: nym-client import-credential --id <ID> <--credential-data <CREDENTIAL_DATA>|--credential-path <CREDENTIAL_PATH>>
Options:
--id <ID>
Id of client that is going to import the credential
--credential-data <CREDENTIAL_DATA>
Explicitly provide the encoded credential data (as base58)
--credential-path <CREDENTIAL_PATH>
Specifies the path to file containing binary credential data
-h, --help
Print help
```
### `list-gateways`
```
List all registered with gateways
Usage: nym-client list-gateways [OPTIONS] --id <ID>
Options:
--id <ID> Id of client we want to list gateways for
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
### `switch-gateway`
```
Change the currently active gateway. Note that you must have already registered with the new gateway!
Usage: nym-client switch-gateway --id <ID> --gateway-id <GATEWAY_ID>
Options:
--id <ID> Id of client we want to list gateways for
--gateway-id <GATEWAY_ID> Id of the gateway we want to switch to
-h, --help Print help
```
### `build-info`
```
Show build information of this binary
Usage: nym-client build-info [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
Example output:
```
Binary Name: nym-client
Build Timestamp: 2024-05-07T13:11:43.523733081Z
Build Version: 1.1.34
Commit SHA: 7d233a4a2fc697a2f97e504db6a3765cc9f2dd49
Commit Date: 2024-04-25T11:27:18.000000000+02:00
Commit Branch: max/auto-docs
rustc Version: 1.78.0
rustc Channel: stable
cargo Profile: release
```
### `completions`
```
Generate shell completions
Usage: nym-client completions <SHELL>
Arguments:
<SHELL> [possible values: bash, elvish, fish, power-shell, zsh]
Options:
-h, --help Print help
```
### `generate-fig-spec`
```
Generate Fig specification
Usage: nym-client generate-fig-spec
Options:
-h, --help Print help
```
Example output:
```
const completion: Fig.Spec = {
name: "nym-native-client",
description: "Implementation of the Nym Client",
subcommands: [
{
name: "init",
description: "Initialise a Nym client. Do this first!",
options: [
{
name: "--id",
description: "Id of client we want to create config for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway",
description: "Id of the gateway we are going to connect to",
isRepeatable: true,
args: {
name: "gateway",
isOptional: true,
},
},
{
name: "--nyxd-urls",
description: "Comma separated list of rest endpoints of the nyxd validators",
hidden: true,
isRepeatable: true,
args: {
name: "nyxd_urls",
isOptional: true,
},
},
{
name: "--nym-apis",
description: "Comma separated list of rest endpoints of the API validators",
isRepeatable: true,
args: {
name: "nym_apis",
isOptional: true,
},
},
{
name: "--custom-mixnet",
description: "Path to .json file containing custom network specification",
hidden: true,
isRepeatable: true,
args: {
name: "custom_mixnet",
isOptional: true,
template: "filepaths",
},
},
{
name: "--enabled-credentials-mode",
description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
hidden: true,
isRepeatable: true,
args: {
name: "enabled_credentials_mode",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: "--disable-socket",
description: "Whether to not start the websocket",
isRepeatable: true,
args: {
name: "disable_socket",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: ["-p", "--port"],
description: "Port for the socket (if applicable) to listen on in all subsequent runs",
isRepeatable: true,
args: {
name: "port",
isOptional: true,
},
},
{
name: "--host",
description: "Ip for the socket (if applicable) to listen for requests",
isRepeatable: true,
args: {
name: "host",
isOptional: true,
},
},
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: "--force-tls-gateway",
description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
},
{
name: "--latency-based-selection",
description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
exclusiveOn: [
"--gateway",
],
},
{
name: "--fastmode",
description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
},
{
name: "--no-cover",
description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "run",
description: "Run the Nym client with provided configuration client optionally overriding set parameters",
options: [
{
name: "--id",
description: "Id of client we want to create config for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway",
description: "Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened",
isRepeatable: true,
args: {
name: "gateway",
isOptional: true,
},
},
{
name: "--nyxd-urls",
description: "Comma separated list of rest endpoints of the nyxd validators",
hidden: true,
isRepeatable: true,
args: {
name: "nyxd_urls",
isOptional: true,
},
},
{
name: "--nym-apis",
description: "Comma separated list of rest endpoints of the API validators",
isRepeatable: true,
args: {
name: "nym_apis",
isOptional: true,
},
},
{
name: "--custom-mixnet",
description: "Path to .json file containing custom network specification",
hidden: true,
isRepeatable: true,
args: {
name: "custom_mixnet",
isOptional: true,
template: "filepaths",
},
},
{
name: "--enabled-credentials-mode",
description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
hidden: true,
isRepeatable: true,
args: {
name: "enabled_credentials_mode",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: "--disable-socket",
description: "Whether to not start the websocket",
isRepeatable: true,
args: {
name: "disable_socket",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: ["-p", "--port"],
description: "Port for the socket to listen on",
isRepeatable: true,
args: {
name: "port",
isOptional: true,
},
},
{
name: "--host",
description: "Ip for the socket (if applicable) to listen for requests",
isRepeatable: true,
args: {
name: "host",
isOptional: true,
},
},
{
name: "--fastmode",
description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
},
{
name: "--no-cover",
description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "import-credential",
description: "Import a pre-generated credential",
options: [
{
name: "--id",
description: "Id of client that is going to import the credential",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--credential-data",
description: "Explicitly provide the encoded credential data (as base58)",
isRepeatable: true,
args: {
name: "credential_data",
isOptional: true,
},
},
{
name: "--credential-path",
description: "Specifies the path to file containing binary credential data",
isRepeatable: true,
args: {
name: "credential_path",
isOptional: true,
template: "filepaths",
},
},
{
name: "--version",
hidden: true,
isRepeatable: true,
args: {
name: "version",
isOptional: true,
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "list-gateways",
description: "List all registered with gateways",
options: [
{
name: "--id",
description: "Id of client we want to list gateways for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "add-gateway",
description: "Add new gateway to this client",
options: [
{
name: "--id",
description: "Id of client we want to add gateway for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway-id",
description: "Explicitly specify id of the gateway to register with. If unspecified, a random gateway will be chosen instead",
isRepeatable: true,
args: {
name: "gateway_id",
isOptional: true,
},
},
{
name: "--nym-apis",
description: "Comma separated list of rest endpoints of the API validators",
isRepeatable: true,
args: {
name: "nym_apis",
isOptional: true,
},
},
{
name: "--custom-mixnet",
description: "Path to .json file containing custom network specification",
hidden: true,
isRepeatable: true,
args: {
name: "custom_mixnet",
isOptional: true,
template: "filepaths",
},
},
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: "--force-tls-gateway",
description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
},
{
name: "--latency-based-selection",
description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
exclusiveOn: [
"--gateway-id",
],
},
{
name: "--set-active",
description: "Specify whether this new gateway should be set as the active one",
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "switch-gateway",
description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
options: [
{
name: "--id",
description: "Id of client we want to list gateways for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway-id",
description: "Id of the gateway we want to switch to",
isRepeatable: true,
args: {
name: "gateway_id",
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "build-info",
description: "Show build information of this binary",
options: [
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "completions",
description: "Generate shell completions",
options: [
{
name: ["-h", "--help"],
description: "Print help",
},
],
args: {
name: "shell",
suggestions: [
"bash",
"elvish",
"fish",
"power-shell",
"zsh",
],
},
},
{
name: "generate-fig-spec",
description: "Generate Fig specification",
options: [
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "help",
description: "Print this message or the help of the given subcommand(s)",
subcommands: [
{
name: "init",
description: "Initialise a Nym client. Do this first!",
},
{
name: "run",
description: "Run the Nym client with provided configuration client optionally overriding set parameters",
},
{
name: "import-credential",
description: "Import a pre-generated credential",
},
{
name: "list-gateways",
description: "List all registered with gateways",
},
{
name: "add-gateway",
description: "Add new gateway to this client",
},
{
name: "switch-gateway",
description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
},
{
name: "build-info",
description: "Show build information of this binary",
},
{
name: "completions",
description: "Generate shell completions",
},
{
name: "generate-fig-spec",
description: "Generate Fig specification",
},
{
name: "help",
description: "Print this message or the help of the given subcommand(s)",
},
],
},
],
options: [
{
name: ["-c", "--config-env-file"],
description: "Path pointing to an env file that configures the client",
isRepeatable: true,
args: {
name: "config_env_file",
isOptional: true,
template: "filepaths",
},
},
{
name: "--no-banner",
description: "Flag used for disabling the printed banner in tty",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
};
export default completion;
```
@@ -1,227 +0,0 @@
# `nym-node` Binary Commands
These docs are autogenerated by the `autodocs` script.
**TODO add link**
```
Usage: nym-node [OPTIONS] <COMMAND>
Commands:
build-info Show build information of this binary
bonding-information Show bonding information of this node depending on its currently selected mode
node-details Show details of this node
migrate Attempt to migrate an existing mixnode or gateway into a nym-node
run Start this nym-node
sign Use identity key of this node to sign provided message
help Print this message or the help of the given subcommand(s)
Options:
-c, --config-env-file <CONFIG_ENV_FILE>
Path pointing to an env file that configures the nym-node and overrides any preconfigured values [env: NYMNODE_CONFIG_ENV_FILE_ARG=]
--no-banner
Flag used for disabling the printed banner in tty [env: NYMNODE_NO_BANNER=]
-h, --help
Print help
-V, --version
Print version
```
### `build-info`
```
Show build information of this binary
Usage: nym-node build-info [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
### `bonding-information`
```
Show bonding information of this node depending on its currently selected mode
Usage: nym-node bonding-information [OPTIONS]
Options:
--id <ID> Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
--config-file <CONFIG_FILE> Path to a configuration file of this node [env: NYMNODE_CONFIG=]
--mode <MODE> [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway]
-o, --output <OUTPUT> Specify the output format of the bonding information (`text` or `json`) [default: text] [possible values: text, json]
-h, --help Print help
```
### `node-details`
```
Show details of this node
Usage: nym-node node-details [OPTIONS]
Options:
--id <ID> Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
--config-file <CONFIG_FILE> Path to a configuration file of this node [env: NYMNODE_CONFIG=]
-o, --output <OUTPUT> Specify the output format of the node details (`text` or `json`) [default: text] [possible values: text, json]
-h, --help Print help
```
### `migrate`
```
Attempt to migrate an existing mixnode or gateway into a nym-node
Usage: nym-node migrate [OPTIONS] <--id <ID>|--config-file <CONFIG_FILE>> <NODE_TYPE>
Arguments:
<NODE_TYPE> Type of node (mixnode or gateway) to migrate into a nym-node [possible values: mixnode, gateway]
Options:
--id <ID>
Id of the node that's going to get migrated
--config-file <CONFIG_FILE>
Path to a configuration file of the node that's going to get migrated
--preserve-id
Specify whether to preserve id of the imported node
--public-ips <PUBLIC_IPS>
Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In nearly all circumstances, it's going to be identical to the address you're going to use for bonding [env: NYMNODE_PUBLIC_IPS=]
--hostname <HOSTNAME>
Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env: NYMNODE_HOSTNAME=]
--location <LOCATION>
Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
--http-bind-address <HTTP_BIND_ADDRESS>
Socket address this node will use for binding its http API. default: `0.0.0.0:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
--landing-page-assets-path <LANDING_PAGE_ASSETS_PATH>
Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
--http-access-token <HTTP_ACCESS_TOKEN>
An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env: NYMNODE_HTTP_ACCESS_TOKEN=]
--expose-system-info <EXPOSE_SYSTEM_INFO>
Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=] [possible values: true, false]
--expose-system-hardware <EXPOSE_SYSTEM_HARDWARE>
Specify whether basic system hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
--expose-crypto-hardware <EXPOSE_CRYPTO_HARDWARE>
Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
--mixnet-bind-address <MIXNET_BIND_ADDRESS>
Address this node will bind to for listening for mixnet packets default: `0.0.0.0:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
--nym-api-urls <NYM_API_URLS>
Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
--nyxd-urls <NYXD_URLS>
Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
--wireguard-enabled <WIREGUARD_ENABLED>
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
Socket address this node will use for binding its wireguard interface. default: `0.0.0.0:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
--wireguard-private-network-ip <WIREGUARD_PRIVATE_NETWORK_IP>
Ip address of the private wireguard network. default: `10.1.0.0` [env: NYMNODE_WG_IP_NETWORK=]
--wireguard-announced-port <WIREGUARD_ANNOUNCED_PORT>
Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
--verloc-bind-address <VERLOC_BIND_ADDRESS>
Socket address this node will use for binding its verloc API. default: `0.0.0.0:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
--entry-bind-address <ENTRY_BIND_ADDRESS>
Socket address this node will use for binding its client websocket API. default: `0.0.0.0:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
--announce-ws-port <ANNOUNCE_WS_PORT>
Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
--announce-wss-port <ANNOUNCE_WSS_PORT>
If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
--enforce-zk-nyms <ENFORCE_ZK_NYMS>
Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible values: true, false]
--mnemonic <MNEMONIC>
Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be generated [env: NYMNODE_MNEMONIC=]
--upstream-exit-policy-url <UPSTREAM_EXIT_POLICY_URL>
Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
--open-proxy <OPEN_PROXY>
Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it receives [env: NYMNODE_OPEN_PROXY=] [possible values: true, false]
-h, --help
Print help
```
### `run`
```
Start this nym-node
Usage: nym-node run [OPTIONS]
Options:
--id <ID>
Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
--config-file <CONFIG_FILE>
Path to a configuration file of this node [env: NYMNODE_CONFIG=]
--deny-init
Forbid a new node from being initialised if configuration file for the provided specification doesn't already exist [env: NYMNODE_DENY_INIT=]
--init-only
If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses [env: NYMNODE_INIT_ONLY=]
--mode <MODE>
Specifies the current mode of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway]
-w, --write-changes
If this node has been initialised before, specify whether to write any new changes to the config file [env: NYMNODE_WRITE_CONFIG_CHANGES=]
--bonding-information-output <BONDING_INFORMATION_OUTPUT>
Specify output file for bonding information of this nym-node, i.e. its encoded keys. NOTE: the required bonding information is still a subject to change and this argument should be treated only as a preview of future features [env: NYMNODE_BONDING_INFORMATION_OUTPUT=]
-o, --output <OUTPUT>
Specify the output format of the bonding information (`text` or `json`) [env: NYMNODE_OUTPUT=] [default: text] [possible values: text, json]
--public-ips <PUBLIC_IPS>
Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In nearly all circumstances, it's going to be identical to the address you're going to use for bonding [env: NYMNODE_PUBLIC_IPS=]
--hostname <HOSTNAME>
Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env: NYMNODE_HOSTNAME=]
--location <LOCATION>
Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
--http-bind-address <HTTP_BIND_ADDRESS>
Socket address this node will use for binding its http API. default: `0.0.0.0:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
--landing-page-assets-path <LANDING_PAGE_ASSETS_PATH>
Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
--http-access-token <HTTP_ACCESS_TOKEN>
An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env: NYMNODE_HTTP_ACCESS_TOKEN=]
--expose-system-info <EXPOSE_SYSTEM_INFO>
Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=] [possible values: true, false]
--expose-system-hardware <EXPOSE_SYSTEM_HARDWARE>
Specify whether basic system hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
--expose-crypto-hardware <EXPOSE_CRYPTO_HARDWARE>
Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
--mixnet-bind-address <MIXNET_BIND_ADDRESS>
Address this node will bind to for listening for mixnet packets default: `0.0.0.0:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
--nym-api-urls <NYM_API_URLS>
Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
--nyxd-urls <NYXD_URLS>
Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
--wireguard-enabled <WIREGUARD_ENABLED>
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
Socket address this node will use for binding its wireguard interface. default: `0.0.0.0:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
--wireguard-private-network-ip <WIREGUARD_PRIVATE_NETWORK_IP>
Ip address of the private wireguard network. default: `10.1.0.0` [env: NYMNODE_WG_IP_NETWORK=]
--wireguard-announced-port <WIREGUARD_ANNOUNCED_PORT>
Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
--verloc-bind-address <VERLOC_BIND_ADDRESS>
Socket address this node will use for binding its verloc API. default: `0.0.0.0:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
--entry-bind-address <ENTRY_BIND_ADDRESS>
Socket address this node will use for binding its client websocket API. default: `0.0.0.0:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
--announce-ws-port <ANNOUNCE_WS_PORT>
Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
--announce-wss-port <ANNOUNCE_WSS_PORT>
If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
--enforce-zk-nyms <ENFORCE_ZK_NYMS>
Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible values: true, false]
--mnemonic <MNEMONIC>
Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be generated [env: NYMNODE_MNEMONIC=]
--upstream-exit-policy-url <UPSTREAM_EXIT_POLICY_URL>
Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
--open-proxy <OPEN_PROXY>
Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it receives [env: NYMNODE_OPEN_PROXY=] [possible values: true, false]
-h, --help
Print help
```
### `sign`
```
Use identity key of this node to sign provided message
Usage: nym-node sign [OPTIONS] <--text <TEXT>|--contract-msg <CONTRACT_MSG>>
Options:
--id <ID> Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
--config-file <CONFIG_FILE> Path to a configuration file of this node [env: NYMNODE_CONFIG=]
--text <TEXT> Signs an arbitrary piece of text with your identity key
--contract-msg <CONTRACT_MSG> Signs a transaction-specific payload, that is going to be sent to the smart contract, with your identity key
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
@@ -1,790 +0,0 @@
# `nym-socks5-client` Binary Commands
These docs are autogenerated by the `autodocs` script.
**TODO add link**
```
A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address
Usage: nym-socks5-client [OPTIONS] <COMMAND>
Commands:
init Initialise a Nym client. Do this first!
run Run the Nym client with provided configuration client optionally overriding set parameters
import-credential Import a pre-generated credential
list-gateways List all registered with gateways
add-gateway Add new gateway to this client
switch-gateway Change the currently active gateway. Note that you must have already registered with the new gateway!
build-info Show build information of this binary
completions Generate shell completions
generate-fig-spec Generate Fig specification
help Print this message or the help of the given subcommand(s)
Options:
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file that configures the client
--no-banner Flag used for disabling the printed banner in tty
-h, --help Print help
-V, --version Print version
```
### `init`
```
Initialise a Nym client. Do this first!
Usage: nym-socks5-client init [OPTIONS] --id <ID> --provider <PROVIDER>
Options:
--id <ID>
Id of client we want to create config for
--gateway <GATEWAY>
Id of the gateway we are going to connect to
--force-tls-gateway
Specifies whether the client will attempt to enforce tls connection to the desired gateway
--latency-based-selection
Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly
--nym-apis <NYM_APIS>
Comma separated list of rest endpoints of the API validators
--provider <PROVIDER>
Address of the socks5 provider to send messages to
--use-reply-surbs <USE_REPLY_SURBS>
Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs.
Note that some service providers might not support this.
[possible values: true, false]
-p, --port <PORT>
Port for the socket to listen on in all subsequent runs
--host <HOST>
The custom host on which the socks5 client will be listening for requests
-o, --output <OUTPUT>
[default: text]
[possible values: text, json]
-h, --help
Print help (see a summary with '-h')
```
### `run`
```
Run the Nym client with provided configuration client optionally overriding set parameters
Usage: nym-socks5-client run [OPTIONS] --id <ID>
Options:
--id <ID>
Id of client we want to create config for
--gateway <GATEWAY>
Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened
--nym-apis <NYM_APIS>
Comma separated list of rest endpoints of the API validators
--use-anonymous-replies <USE_ANONYMOUS_REPLIES>
Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs.
Note that some service providers might not support this.
[possible values: true, false]
--provider <PROVIDER>
Address of the socks5 provider to send messages to
-p, --port <PORT>
Port for the socket to listen on
--host <HOST>
The custom host on which the socks5 client will be listening for requests
-h, --help
Print help (see a summary with '-h')
```
### `import-credential`
```
Import a pre-generated credential
Usage: nym-socks5-client import-credential --id <ID> <--credential-data <CREDENTIAL_DATA>|--credential-path <CREDENTIAL_PATH>>
Options:
--id <ID>
Id of client that is going to import the credential
--credential-data <CREDENTIAL_DATA>
Explicitly provide the encoded credential data (as base58)
--credential-path <CREDENTIAL_PATH>
Specifies the path to file containing binary credential data
-h, --help
Print help
```
### `list-gateways`
```
List all registered with gateways
Usage: nym-socks5-client list-gateways [OPTIONS] --id <ID>
Options:
--id <ID> Id of client we want to list gateways for
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
### `add-gateway`
```
Add new gateway to this client
Usage: nym-socks5-client add-gateway [OPTIONS] --id <ID>
Options:
--id <ID> Id of client we want to add gateway for
--gateway-id <GATEWAY_ID> Explicitly specify id of the gateway to register with. If unspecified, a random gateway will be chosen instead
--force-tls-gateway Specifies whether the client will attempt to enforce tls connection to the desired gateway
--latency-based-selection Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly
--set-active Specify whether this new gateway should be set as the active one
--nym-apis <NYM_APIS> Comma separated list of rest endpoints of the API validators
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
### `build-info`
```
Show build information of this binary
Usage: nym-socks5-client build-info [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
Example output:
```
Binary Name: nym-socks5-client
Build Timestamp: 2024-05-07T13:11:43.523733081Z
Build Version: 1.1.34
Commit SHA: 7d233a4a2fc697a2f97e504db6a3765cc9f2dd49
Commit Date: 2024-04-25T11:27:18.000000000+02:00
Commit Branch: max/auto-docs
rustc Version: 1.78.0
rustc Channel: stable
cargo Profile: release
```
### `completions`
```
Generate shell completions
Usage: nym-socks5-client completions <SHELL>
Arguments:
<SHELL> [possible values: bash, elvish, fish, power-shell, zsh]
Options:
-h, --help Print help
```
### `generate-fig-spec`
```
Generate Fig specification
Usage: nym-socks5-client generate-fig-spec
Options:
-h, --help Print help
```
Example output:
```
const completion: Fig.Spec = {
name: "nym-socks5-client",
description: "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address",
subcommands: [
{
name: "init",
description: "Initialise a Nym client. Do this first!",
options: [
{
name: "--id",
description: "Id of client we want to create config for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway",
description: "Id of the gateway we are going to connect to",
isRepeatable: true,
args: {
name: "gateway",
isOptional: true,
},
},
{
name: "--nyxd-urls",
description: "Comma separated list of rest endpoints of the nyxd validators",
hidden: true,
isRepeatable: true,
args: {
name: "nyxd_urls",
isOptional: true,
},
},
{
name: "--nym-apis",
description: "Comma separated list of rest endpoints of the API validators",
isRepeatable: true,
args: {
name: "nym_apis",
isOptional: true,
},
},
{
name: "--custom-mixnet",
description: "Path to .json file containing custom network specification",
hidden: true,
isRepeatable: true,
args: {
name: "custom_mixnet",
isOptional: true,
template: "filepaths",
},
},
{
name: "--enabled-credentials-mode",
description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
hidden: true,
isRepeatable: true,
args: {
name: "enabled_credentials_mode",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: "--provider",
description: "Address of the socks5 provider to send messages to",
isRepeatable: true,
args: {
name: "provider",
},
},
{
name: "--use-reply-surbs",
description: "Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs",
isRepeatable: true,
args: {
name: "use_reply_surbs",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: ["-p", "--port"],
description: "Port for the socket to listen on in all subsequent runs",
isRepeatable: true,
args: {
name: "port",
isOptional: true,
},
},
{
name: "--host",
description: "The custom host on which the socks5 client will be listening for requests",
isRepeatable: true,
args: {
name: "host",
isOptional: true,
},
},
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: "--force-tls-gateway",
description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
},
{
name: "--latency-based-selection",
description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
exclusiveOn: [
"--gateway",
],
},
{
name: "--fastmode",
description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
},
{
name: "--no-cover",
description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
},
{
name: ["-h", "--help"],
description: "Print help (see more with '--help')",
},
],
},
{
name: "run",
description: "Run the Nym client with provided configuration client optionally overriding set parameters",
options: [
{
name: "--id",
description: "Id of client we want to create config for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway",
description: "Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened",
isRepeatable: true,
args: {
name: "gateway",
isOptional: true,
},
},
{
name: "--nyxd-urls",
description: "Comma separated list of rest endpoints of the nyxd validators",
hidden: true,
isRepeatable: true,
args: {
name: "nyxd_urls",
isOptional: true,
},
},
{
name: "--nym-apis",
description: "Comma separated list of rest endpoints of the API validators",
isRepeatable: true,
args: {
name: "nym_apis",
isOptional: true,
},
},
{
name: "--custom-mixnet",
description: "Path to .json file containing custom network specification",
hidden: true,
isRepeatable: true,
args: {
name: "custom_mixnet",
isOptional: true,
template: "filepaths",
},
},
{
name: "--enabled-credentials-mode",
description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
hidden: true,
isRepeatable: true,
args: {
name: "enabled_credentials_mode",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: "--use-anonymous-replies",
description: "Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs",
isRepeatable: true,
args: {
name: "use_anonymous_replies",
isOptional: true,
suggestions: [
"true",
"false",
],
},
},
{
name: "--provider",
description: "Address of the socks5 provider to send messages to",
isRepeatable: true,
args: {
name: "provider",
isOptional: true,
},
},
{
name: ["-p", "--port"],
description: "Port for the socket to listen on",
isRepeatable: true,
args: {
name: "port",
isOptional: true,
},
},
{
name: "--host",
description: "The custom host on which the socks5 client will be listening for requests",
isRepeatable: true,
args: {
name: "host",
isOptional: true,
},
},
{
name: "--geo-routing",
description: "Set geo-aware mixnode selection when sending mixnet traffic, for experiments only",
hidden: true,
isRepeatable: true,
args: {
name: "geo_routing",
isOptional: true,
},
},
{
name: "--fastmode",
description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
},
{
name: "--no-cover",
description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
},
{
name: "--medium-toggle",
description: "Enable medium mixnet traffic, for experiments only. This includes things like disabling cover traffic, no per hop delays, etc",
},
{
name: "--outfox",
},
{
name: ["-h", "--help"],
description: "Print help (see more with '--help')",
},
],
},
{
name: "import-credential",
description: "Import a pre-generated credential",
options: [
{
name: "--id",
description: "Id of client that is going to import the credential",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--credential-data",
description: "Explicitly provide the encoded credential data (as base58)",
isRepeatable: true,
args: {
name: "credential_data",
isOptional: true,
},
},
{
name: "--credential-path",
description: "Specifies the path to file containing binary credential data",
isRepeatable: true,
args: {
name: "credential_path",
isOptional: true,
template: "filepaths",
},
},
{
name: "--version",
hidden: true,
isRepeatable: true,
args: {
name: "version",
isOptional: true,
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "list-gateways",
description: "List all registered with gateways",
options: [
{
name: "--id",
description: "Id of client we want to list gateways for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "add-gateway",
description: "Add new gateway to this client",
options: [
{
name: "--id",
description: "Id of client we want to add gateway for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway-id",
description: "Explicitly specify id of the gateway to register with. If unspecified, a random gateway will be chosen instead",
isRepeatable: true,
args: {
name: "gateway_id",
isOptional: true,
},
},
{
name: "--nym-apis",
description: "Comma separated list of rest endpoints of the API validators",
isRepeatable: true,
args: {
name: "nym_apis",
isOptional: true,
},
},
{
name: "--custom-mixnet",
description: "Path to .json file containing custom network specification",
hidden: true,
isRepeatable: true,
args: {
name: "custom_mixnet",
isOptional: true,
template: "filepaths",
},
},
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: "--force-tls-gateway",
description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
},
{
name: "--latency-based-selection",
description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
exclusiveOn: [
"--gateway-id",
],
},
{
name: "--set-active",
description: "Specify whether this new gateway should be set as the active one",
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "switch-gateway",
description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
options: [
{
name: "--id",
description: "Id of client we want to list gateways for",
isRepeatable: true,
args: {
name: "id",
},
},
{
name: "--gateway-id",
description: "Id of the gateway we want to switch to",
isRepeatable: true,
args: {
name: "gateway_id",
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "build-info",
description: "Show build information of this binary",
options: [
{
name: ["-o", "--output"],
isRepeatable: true,
args: {
name: "output",
isOptional: true,
suggestions: [
"text",
"json",
],
},
},
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "completions",
description: "Generate shell completions",
options: [
{
name: ["-h", "--help"],
description: "Print help",
},
],
args: {
name: "shell",
suggestions: [
"bash",
"elvish",
"fish",
"power-shell",
"zsh",
],
},
},
{
name: "generate-fig-spec",
description: "Generate Fig specification",
options: [
{
name: ["-h", "--help"],
description: "Print help",
},
],
},
{
name: "help",
description: "Print this message or the help of the given subcommand(s)",
subcommands: [
{
name: "init",
description: "Initialise a Nym client. Do this first!",
},
{
name: "run",
description: "Run the Nym client with provided configuration client optionally overriding set parameters",
},
{
name: "import-credential",
description: "Import a pre-generated credential",
},
{
name: "list-gateways",
description: "List all registered with gateways",
},
{
name: "add-gateway",
description: "Add new gateway to this client",
},
{
name: "switch-gateway",
description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
},
{
name: "build-info",
description: "Show build information of this binary",
},
{
name: "completions",
description: "Generate shell completions",
},
{
name: "generate-fig-spec",
description: "Generate Fig specification",
},
{
name: "help",
description: "Print this message or the help of the given subcommand(s)",
},
],
},
],
options: [
{
name: ["-c", "--config-env-file"],
description: "Path pointing to an env file that configures the client",
isRepeatable: true,
args: {
name: "config_env_file",
isOptional: true,
template: "filepaths",
},
},
{
name: "--no-banner",
description: "Flag used for disabling the printed banner in tty",
},
{
name: ["-h", "--help"],
description: "Print help",
},
{
name: ["-V", "--version"],
description: "Print version",
},
],
};
export default completion;
```
@@ -1,192 +0,0 @@
# `nymvisor` Binary Commands
These docs are autogenerated by the `autodocs` script.
**TODO add link**
```
Usage: nymvisor [OPTIONS] <COMMAND>
Commands:
init Initialise a nymvisor instance with persistent Config.toml file
run Run the associated daemon with the preconfigured settings
build-info Show build information of this binary
daemon-build-info Show build information of the associated daemon
add-upgrade Queues up another upgrade for the associated daemon
config Show configuration options being used by this instance of nymvisor
help Print this message or the help of the given subcommand(s)
Options:
-c, --config-env-file <CONFIG_ENV_FILE>
Path pointing to an env file that configures the nymvisor and overrides any preconfigured values
-h, --help
Print help
-V, --version
Print version
```
### `init`
```
Initialise a nymvisor instance with persistent Config.toml file
Usage: nymvisor init [OPTIONS] <DAEMON_BINARY>
Arguments:
<DAEMON_BINARY> Path to the daemon's executable
Options:
--id <ID>
ID specifies the human readable ID of this particular nymvisor instance. Can be overridden with $NYMVISOR_ID environmental variable
--upstream-base-upgrade-url <UPSTREAM_BASE_UPGRADE_URL>
Sets the base url of the upstream source for obtaining upgrade information for the deaemon. It will be used fo constructing the full url, i.e. $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL/$DAEMON_NAME/upgrade-info.json Can be overridden with $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL environmental variable
--upstream-polling-rate <UPSTREAM_POLLING_RATE>
Specifies the rate of polling the upstream url for upgrade information. default: 1h Can be overridden with $NYMVISOR_UPSTREAM_POLLING_RATE
--disable-nymvisor-logs
If enabled, this will disable `nymvisor` logs (but not the underlying process) Can be overridden with $NYMVISOR_DISABLE_LOGS environmental variable
--upgrade-data-directory <UPGRADE_DATA_DIRECTORY>
Set custom directory for upgrade data - binaries and upgrade plans. If not set, the global nymvisors' data directory will be used instead. Can be overridden with $NYMVISOR_UPGRADE_DATA_DIRECTORY environmental variable
--daemon-home <DAEMON_HOME>
The location where the `nymvisor/` directory is kept that contains the auxiliary files associated with the underlying daemon, such as any backups or current version information. (e.g. $HOME/.nym/nym-api/my-nym-api, $HOME/.nym/mixnodes/my-mixnode, etc.). Can be overridden with $DAEMON_HOME environmental variable
--daemon-absolute-upstream-upgrade-url <DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL>
Override url to the upstream source for upgrade plans for this daeamon. The Url has to point to an endpoint containing a valid [`UpgradeInfo`] json. Note: if set this takes precedence over `upstream_base_upgrade_url` Can be overridden with $DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL environmental variable
--allow-download-upgrade-binaries <ALLOW_DOWNLOAD_UPGRADE_BINARIES>
If set to true, this will enable auto-downloading of new binaries using the url provided in the `upgrade-info.json` Can be overridden with $DAEMON_ALLOW_BINARIES_DOWNLOAD environmental variable [possible values: true, false]
--enforce-download-checksum <ENFORCE_DOWNLOAD_CHECKSUM>
If enabled nymvisor will require that a checksum is provided in the upgrade plan for the binary to be downloaded. If disabled, nymvisor will not require a checksum to be provided, but still check the checksum if one is provided. Can be overridden with $DAEMON_ENFORCE_DOWNLOAD_CHECKSUM environmental variable [possible values: true, false]
--restart-daemon-after-upgrade <RESTART_DAEMON_AFTER_UPGRADE>
If enabled, nymvisor will restart the subprocess with the same command-line arguments and flags (but with the new binary) after a successful upgrade. Otherwise (if disabled), nymvisor will stop running after an upgrade and will require the system administrator to manually restart it. Note restart is only after the upgrade and does not auto-restart the subprocess after an error occurs. Can be overridden with $DAEMON_RESTART_AFTER_UPGRADE environmental variable [possible values: true, false]
--restart-daemon-on-failure
If enabled, nymvisor will restart the subprocess with the same command-line arguments and flags after it has crashed Can be overridden with $DAEMON_RESTART_ON_FAILURE environmental variable
--on-failure-daemon-restart-delay <ON_FAILURE_DAEMON_RESTART_DELAY>
If `restart_on_failure` is enabled, the following value defines the amount of time `nymvisor` shall wait before restarting the subprocess. Can be overridden with $DAEMON_FAILURE_RESTART_DELAY environmental variable
--max-daemon-startup-failures <MAX_DAEMON_STARTUP_FAILURES>
Defines the maximum number of startup failures the subprocess can experience in a quick succession before no further restarts will be attempted and `nymvisor` will exit. Can be overridden with $DAEMON_MAX_STARTUP_FAILURES environmental variable
--startup-period-duration <STARTUP_PERIOD_DURATION>
Defines the length of time during which the subprocess is still considered to be in the startup phase when its failures are going to be considered in `max_startup_failures`. Can be overridden with $DAEMON_STARTUP_PERIOD_DURATION environmental variable
--daemon-shutdown-grace-period <DAEMON_SHUTDOWN_GRACE_PERIOD>
Specifies the amount of time `nymvisor` is willing to wait for the subprocess to undergo graceful shutdown after receiving an interrupt (for either an upgrade or shutdown of the `nymvisor` itself) Once the time passes, a kill signal is going to be sent instead. Can be overridden with $DAEMON_SHUTDOWN_GRACE_PERIOD environmental variable
--daemon-backup-data-directory <DAEMON_BACKUP_DATA_DIRECTORY>
Set custom backup directory for daemon data. If not set, the daemon's home directory will be used instead. Can be overridden with $DAEMON_BACKUP_DATA_DIRECTORY environmental variable
--unsafe-skip-backup
If enabled, `nymvisor` will perform upgrades directly without performing any backups. default: false Can be overridden with $DAEMON_UNSAFE_SKIP_BACKUP environmental variable
-o, --output <OUTPUT>
[default: text] [possible values: text, json]
-h, --help
Print help
```
### `run`
```
Run the associated daemon with the preconfigured settings
Usage: nymvisor run [DAEMON_ARGS]...
Arguments:
[DAEMON_ARGS]...
Options:
-h, --help Print help
```
### `build-info`
```
Show build information of this binary
Usage: nymvisor build-info [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
Example output:
```
Binary Name: nymvisor
Build Timestamp: 2024-05-07T13:11:43.523733081Z
Build Version: 0.1.0
Commit SHA: 7d233a4a2fc697a2f97e504db6a3765cc9f2dd49
Commit Date: 2024-04-25T11:27:18.000000000+02:00
Commit Branch: max/auto-docs
rustc Version: 1.78.0
rustc Channel: stable
cargo Profile: release
```
### `daemon-build-info`
```
Show build information of the associated daemon
Usage: nymvisor daemon-build-info [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
Example output:
```
Binary Name: nym-mixnode
Build Timestamp: 2024-03-22T17:49:30.278145161Z
Build Version: 1.1.34
Commit SHA: 31bbfdecf5ea6deff69bd72a0bccd9dddae1003f
Commit Date: 2024-02-19T10:52:15.000000000+01:00
Commit Branch: max/docs-overhaul-1
rustc Version: 1.74.1
rustc Channel: stable
cargo Profile: release
```
### `add-upgrade`
```
Queues up another upgrade for the associated daemon
Usage: nymvisor add-upgrade [OPTIONS] --upgrade-name <UPGRADE_NAME> <DAEMON_BINARY>
Arguments:
<DAEMON_BINARY> Path to the daemon's upgrade executable
Options:
--upgrade-name <UPGRADE_NAME> Name of this upgrade
--force Overwrite existing upgrade binary / upgrade-info.json file
--add-binary Indicate that this command should only add binary to an *existing* scheduled upgrade
--now Force the upgrade to happen immediately
--publish-date <PUBLISH_DATE> Specifies the publish date metadata field of this upgrade. If unset, the current time will be used
--upgrade-time <UPGRADE_TIME> Specifies the time at which the provided upgrade will be performed (RFC3339 formatted). If left unset, the upgrade will be performed in 15min
--upgrade-delay <UPGRADE_DELAY> Specifies delay until the provided upgrade is going to get performed. If let unset, the upgrade will be performed in 15min
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
### `config`
```
Show configuration options being used by this instance of nymvisor
Usage: nymvisor config [OPTIONS]
Options:
-o, --output <OUTPUT> [default: text] [possible values: text, json]
-h, --help Print help
```
Example output:
```
id: nym-mixnode-default
daemon name: nym-mixnode
daemon home: /home/xen/.nym/mixnodes/my-node
upstream base upgrade url: https://nymtech.net/.wellknown/
disable nymvisor logs: false
CUSTOM upgrade data directory ""
upstream absolute upgrade url: ""
allow binaries download: true
enforce download checksum: true
restart after upgrade: true
restart on failure: false
on failure restart delay: 10s
max startup failures: 10
startup period duration: 2m
shutdown grace period: 10s
CUSTOM backup data directory ""
UNSAFE skip backups false
```
-311
View File
@@ -1,311 +0,0 @@
use log::info;
use std::fs::File;
use std::io::{self, Write};
use std::process::{Command, Output};
use std::{fs, vec};
const PATH: &str = "./autodoc-generated-markdown/";
fn main() -> io::Result<()> {
env_logger::init();
// TODO try and write to grab the commands from Clap at some point
let commands_with_subcommands = vec![
(
"../../target/release/nym-api",
vec!["init", "run", "build-info"],
),
(
"../../target/release/nym-client",
vec![
"init",
"run",
"import-credential",
"list-gateways",
"switch-gateway",
"build-info",
"completions",
"generate-fig-spec",
],
),
(
"../../target/release/nym-socks5-client",
vec![
"init",
"run",
"import-credential",
"list-gateways",
"add-gateway",
"build-info",
"completions",
"generate-fig-spec",
],
),
(
"../../target/release/nym-node",
vec![
"build-info",
"bonding-information",
"node-details",
"migrate",
"run",
"sign",
],
),
(
"../../target/release/nymvisor",
vec![
"init",
"run",
"build-info",
"daemon-build-info",
"add-upgrade",
"config",
],
),
];
let commands_with_subsubcommands = vec![(
"../../target/release/nym-cli",
vec![
(
"account",
vec!["create", "balance", "pub-key", "send", "send-multiple"],
),
("signature", vec!["sign", "verify"]),
(
"coconut",
vec![
"generate-freepass",
"issue-credentials",
"recover-credentials",
"import-credential",
],
),
("block", vec!["get", "time", "current-height"]),
(
"cosmwasm",
vec![
"upload",
"init",
"generate-init-message",
"migrate",
"execute",
],
),
("tx", vec!["get", "query"]),
(
"vesting-schedule",
vec!["create", "query", "vested-balance", "withdraw-vested"],
),
("mixnet", vec!["query", "delegators", "operators"]),
("generate-fig", vec![""]),
],
)];
for (main_command, subcommands) in commands_with_subcommands {
let last_word = get_last_word_from_filepath(main_command);
info!("{last_word:#?}");
if !fs::metadata(PATH)
.map(|metadata| metadata.is_dir())
.unwrap_or(false)
{
fs::create_dir_all(PATH)?;
}
let mut file = File::create(format!("{}/{}-commands.md", PATH, last_word.unwrap()))?;
writeln!(
file,
"# {} Binary Commands",
format!("`{}`", last_word.unwrap())
)?;
writeln!(
file,
"\nThese docs are autogenerated by the `autodocs` script.
\n**TODO add link**"
)?;
let output = Command::new(main_command).arg("--help").output()?;
write_output_to_file(&mut file, output)?;
for subcommand in subcommands {
execute_command(&mut file, main_command, subcommand, None)?;
}
}
// nym-cli has subsubcommands so needs its own loop
for (main_command, subcommands) in &commands_with_subsubcommands {
let last_word = get_last_word_from_filepath(main_command);
info!("{last_word:#?}");
let mut file = File::create(format!("{}/{}-commands.md", PATH, last_word.unwrap()))?;
writeln!(
file,
"# {} Binary Commands",
format!("`{}`", last_word.unwrap())
)?;
writeln!(
file,
"\nThese docs are autogenerated by the `autodocs` script.
\n**TODO add link**"
)?;
let output = Command::new(main_command).arg("--help").output()?;
write_output_to_file(&mut file, output)?;
for (subcommand, subsubcommands) in subcommands {
writeln!(file, "\n### `{}` ", subcommand)?;
let output = Command::new(main_command)
.arg(subcommand)
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(&mut file, output)?;
} else {
info!("empty stdout - nothing to write");
}
for subsubcommand in subsubcommands {
execute_command(&mut file, main_command, subcommand, Some(subsubcommand))?;
/*
println!(
"{:#?} {:#?} {:#?}",
last_word.unwrap(),
subcommand,
subsubcommand
);
*/
}
}
}
Ok(())
}
fn get_last_word_from_filepath(filepath: &str) -> Option<&str> {
let parts: Vec<&str> = filepath.split('/').collect();
parts.last().copied()
}
fn execute_command(
file: &mut File,
main_command: &str,
subcommand: &str,
subsubcommand: Option<&str>,
) -> io::Result<()> {
// checking for the nym-cli subsubcommands
if subsubcommand.is_some() {
writeln!(file, "\n### `{} {}`", subcommand, subsubcommand.unwrap())?;
info!("executing {} {} --help ", main_command, subcommand);
let output = Command::new(main_command)
.arg(subcommand)
.arg(subsubcommand.unwrap())
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(file, output)?;
} else {
info!("empty stdout - nothing to write");
}
// just subcommands
} else {
writeln!(file, "\n### `{}`", subcommand)?;
// println!("{}", subcommand);
// execute help
let output = Command::new(main_command)
.arg(subcommand)
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(file, output)?;
} else {
info!("empty stdout - nothing to write");
}
// then execute w/out help: the majority of functions will fail since you're not passing
// required params but thats fine as we can just not render stderr into the final file.
//
// this check is basically checking for the rare commands (rn just one) that start a process with no params
// perhaps if this list grows we could just add a timeout and shunt the running and writing
// into a thread with a timeout or something but for right now its fine / thats overkill
if get_last_word_from_filepath(main_command).unwrap() == "nym-node"
|| get_last_word_from_filepath(main_command).unwrap() == "nym-api"
|| get_last_word_from_filepath(main_command).unwrap() == "nymvisor"
&& subcommand == "run"
{
info!("SKIPPING {} {}", main_command, subcommand);
} else {
info!("executing {} {}", main_command, subcommand);
let output = Command::new(main_command).arg(subcommand).output()?;
if !output.stdout.is_empty() {
writeln!(file, "Example output:")?;
write_output_to_file(file, output)?;
} else {
info!("empty stdout - nothing to write");
if !&output.stderr.is_empty() {
info!("stderr: {:#?}", String::from_utf8_lossy(&output.stderr));
}
}
}
}
Ok(())
}
/*
fn execute_command(file: &mut File, main_command: &str, subcommand: &str) -> io::Result<()> {
// title
writeln!(file, "\n### `{}`", subcommand)?;
// first execute the command with `--help`
info!("executing {} {} --help ", main_command, subcommand);
let output = Command::new(main_command)
.arg(subcommand)
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(file, output)?;
} else {
info!("empty stdout - nothing to write");
}
// then execute w/out help: the majority of functions will fail since you're not passing
// required params but thats fine as we can just not render stderr into the final file.
//
// this check is basically checking for the rare commands (rn just one) that start a process with no params
// perhaps if this list grows we could just add a timeout and shunt the running and writing
// into a thread with a timeout or something but for right now its fine / thats overkill
if get_last_word_from_filepath(main_command).unwrap() == "nym-node"
|| get_last_word_from_filepath(main_command).unwrap() == "nym-api"
|| get_last_word_from_filepath(main_command).unwrap() == "nymvisor" && subcommand == "run"
{
info!("SKIPPING {} {}", main_command, subcommand);
} else {
info!("executing {} {}", main_command, subcommand);
let output = Command::new(main_command).arg(subcommand).output()?;
if !output.stdout.is_empty() {
writeln!(file, "Example output:")?;
write_output_to_file(file, output)?;
} else {
info!("empty stdout - nothing to write");
if !&output.stderr.is_empty() {
info!("stderr: {:#?}", String::from_utf8_lossy(&output.stderr));
}
}
}
Ok(())
}
*/
fn write_output_to_file(file: &mut File, output: Output) -> io::Result<()> {
writeln!(file, "```")?;
file.write_all(&output.stdout)?;
writeln!(file, "```")?;
// if we want to keep this we could create 2 copies if you run this in a certain mode ("debug"
// oder so) so you can see the stderr but in reality, we want dont want the errors in teh md
// file and also probaly not write 'stdout', but just have <command><output> in a clean fashion
if !&output.stderr.is_empty() {
info!("stderr: {:#?}", String::from_utf8_lossy(&output.stderr));
}
Ok(())
}
+2 -1
View File
@@ -1,4 +1,3 @@
#
# Summary
- [Introduction](introduction.md)
@@ -24,6 +23,8 @@
- [Linux](nymvpn/gui-linux.md)
- [MacOS](nymvpn/gui-mac.md)
- [CLI](nymvpn/cli.md)
- [Linux](nymvpn/cli-linux.md)
- [MacOS](nymvpn/cli-mac.md)
- [Troubleshooting](nymvpn/troubleshooting.md)
- [NymVPN FAQ](nymvpn/faq.md)
- [NymConnect X Monero](tutorials/monero.md)
@@ -1,4 +1,4 @@
# NymVPN alpha CLI Guide
# NymVPN alpha CLI: Guide for GNU/Linux
```admonish info
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
@@ -8,7 +8,7 @@ NymVPN is an experimental software and it's for testing purposes only. All users
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
1. Open Github [releases page]({{nym_vpn_releases}}) and download the CLI latest binary for your system
1. Open Github [releases page]({{nym_vpn_releases}}) and download the binary for Debian based Linux
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
```sh
@@ -25,12 +25,17 @@ tar -xvf <BINARY>.tar.gz
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
```
4. Make executable:
4. Make executable by running:
```sh
# make sure you are in the right sub-directory
chmod u+x ./nym-vpn-cli
```
5. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
## Run NymVPN
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
@@ -42,7 +47,7 @@ Make sure your terminal is open in the same directory as your `nym-vpn-cli` bina
```sh
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WIREGUARD_IP>
```
3. To choose different Gateways, visit [explorer.nymtech.net/network-components/gateways](https://explorer.nymtech.net/network-components/gateways) and copy-paste an identity key of your choice
3. To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways) and pick one
4. See all possibilities in [command explanation](#cli-commands-and-options) section below
In case of errors, see [troubleshooting section](troubleshooting.md).
@@ -51,16 +56,16 @@ In case of errors, see [troubleshooting section](troubleshooting.md).
The basic syntax of `nym-vpn-cli` is:
```sh
sudo ./nym-vpn-cli <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WG_IP>
```
* To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://explorer.nymtech.net/network-components/gateways)
* To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
* To see all possibilities run with `--help` flag:
```sh
./nym-vpn-cli --help
```
~~~admonish example collapsible=true title="Console output"
```sh
Usage: nym-vpn-cli [OPTIONS] <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
Usage: nym-vpn-cli [OPTIONS]
Options:
-c, --config-env-file <CONFIG_ENV_FILE>
@@ -71,13 +76,11 @@ Options:
Mixnet public ID of the entry gateway
--entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
Auto-select entry gateway by country ISO
--entry-gateway-low-latency
Auto-select entry gateway by latency
--exit-router-address <EXIT_ROUTER_ADDRESS>
Mixnet recipient address
--exit-gateway-id <EXIT_GATEWAY_ID>
--exit-gateway-country <EXIT_GATEWAY_COUNTRY>
--exit-router-country <EXIT_ROUTER_COUNTRY>
Mixnet recipient address
--enable-wireguard
Enable the wireguard traffic between the client and the entry gateway
@@ -85,10 +88,8 @@ Options:
Associated private key
--wg-ip <WG_IP>
The IP address of the wireguard interface used for the first hop to the entry gateway
--nym-ipv4 <NYM_IPV4>
The IPv4 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-ipv6 <NYM_IPV6>
The IPv6 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-ip <NYM_IP>
The IP address of the nym TUN device that wraps IP packets in sphinx packets
--nym-mtu <NYM_MTU>
The MTU of the nym TUN device that wraps IP packets in sphinx packets
--disable-routing
@@ -124,19 +125,3 @@ Here is a list of the options and their descriptions. Some are essential, some a
- `--ip` is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
- `--mtu`: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
- `--disable-routing`: Disable routing all traffic through the VPN TUN device.
## Testnet environment
If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:
1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
1. Check available Gateways at [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
2. Run with a flag `-c`
```sh
sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
```
@@ -1,35 +0,0 @@
# NymVPN Command Line Interface (CLI)
```admonish info
Our alpha testing round is done with participants at live workshop events. This guide will not work for everyone, as the NymVPN source code is not yet publicly accessible. The alpha testing is done on Nym testnet Sandbox environment, this configuration is limited and will not work in the future.
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
```
Follow the simple [automated script](#automated-script-for-cli-installation) below to install and run NymVPN CLI. If you prefer to do a manual setup follow the steps in the guide for [Linux](cli-linux.md) or [MacOS](cli-mac.md).
Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums or download the binaries directly.
## Automated Script for CLI Installation
We wrote a [script](https://gist.github.com/serinko/d65450653d6bbafacbcee71c9cb8fb31) which does download of the CLI, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
1. Open a terminal window in a directory where you want the script and NymVPN CLI binary be downloaded and run
```sh
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/raw/d39f98dbb36ccff761a7e940073388a6fe7b73fe/execute-nym-vpn-cli-binary.sh && chmod u+x execute-nym-vpn-cli-binary.sh && sudo -E ./execute-nym-vpn-cli-binary.sh
```
2. Follow the prompts in the program
3. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
* It prints a JSON view of existing Gateways and prompt you to:
- *Make sure to use two different Gateways for entry and exit!*
- `enter a gateway ID:` paste one of the values labeled with a key `"identityKey"` printed above (without `" "`)
- `enter an exit address:` paste one of the values labeled with a key `"address"` printed above (without `" "`)
- `do you want five hop or two hop?`: type `five` or `two`
- `enable WireGuard? (yes/no):` if you chose yes, find your private key and wireguard IP [here](https://nymvpn.com/en/alpha)
To run `nym-vpn-cli` again, reconnect your wifi, move to the directory of your CLI binary `cd ~/nym-vpn-cli-dir` and follow the guide for [Linux](cli-linux.md#run-nymvpn) or [MacOS](cli-mac.md#run-nymvpn). If you find it too difficult, just run this script again - like in step \#3 above.
In case of errors check out the [troubleshooting](troubleshooting.md) section.
+21 -137
View File
@@ -1,151 +1,35 @@
# NymVPN alpha CLI Guide
# NymVPN Command Line Interface (CLI)
```admonish info
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
Our alpha testing round is done with participants at live workshop events. This guide will not work for everyone, as the NymVPN source code is not yet publicly accessible. The alpha testing is done on Nym testnet Sandbox environment, this configuration is limited and will not work in the future.
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
```
## Installation
Follow the simple [automated script](#automated-script-for-cli-installation) below to install and run NymVPN CLI. If you prefer to do a manual setup follow the steps in the guide for [Linux](cli-linux.md) or [MacOS](cli-mac.md).
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums or download the binaries directly.
1. Open Github [releases page]({{nym_vpn_releases}}) and download the CLI latest binary for your system
## Automated Script for CLI Installation
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
We wrote a [script](https://gist.github.com/serinko/d65450653d6bbafacbcee71c9cb8fb31) which does download of the CLI, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
1. Open a terminal window in a directory where you want the script and NymVPN CLI binary be downloaded and run
```sh
echo "<SHA_STRING>" | shasum -a 256 -c
# choose a correct one according to your binary, this is just an example
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_amd64.tar.gz" | shasum -a 256 -c
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/raw/d39f98dbb36ccff761a7e940073388a6fe7b73fe/execute-nym-vpn-cli-binary.sh && chmod u+x execute-nym-vpn-cli-binary.sh && sudo -E ./execute-nym-vpn-cli-binary.sh
```
3. Extract files:
```sh
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
```
2. Follow the prompts in the program
4. Make executable:
```sh
# make sure you are in the right sub-directory
chmod u+x nym-vpn-cli
```
3. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
## Run NymVPN
* It prints a JSON view of existing Gateways and prompt you to:
- *Make sure to use two different Gateways for entry and exit!*
- `enter a gateway ID:` paste one of the values labeled with a key `"identityKey"` printed above (without `" "`)
- `enter an exit address:` paste one of the values labeled with a key `"address"` printed above (without `" "`)
- `do you want five hop or two hop?`: type `five` or `two`
- `enable WireGuard? (yes/no):` if you chose yes, find your private key and wireguard IP [here](https://nymvpn.com/en/alpha)
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
To run `nym-vpn-cli` again, reconnect your wifi, move to the directory of your CLI binary `cd ~/nym-vpn-cli-dir` and follow the guide for [Linux](cli-linux.md#run-nymvpn) or [MacOS](cli-mac.md#run-nymvpn). If you find it too difficult, just run this script again - like in step \#3 above.
Make sure your terminal is open in the same directory as your `nym-vpn-cli` binary.
1. Run it as root with `sudo` - the command will look like this with specified arguments:
```sh
# choose only one conditional --argument listed in {brackets}
sudo ./nym-vpn-cli { --exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY> }
```
2. To choose different Gateways, visit [explorer.nymtech.net/network-components/gateways](https://explorer.nymtech.net/network-components/gateways) and copy-paste an identity key of your choice
```admonish note
Nym Exit Gateway functionality was implemented just recently and not all the Gateways are upgraded and ready to handle the VPN connections. If you want to make sure you are connecting to a Gateway with an embedded Network Requester, IP Packet Router and applied Nym exit policy, visit [this page](https://nymtech.net/events/fast-and-furious), scroll down to the list and search Gateways with all the functionalities enabled.
```
3. See all possibilities in [command explanation](#cli-commands-and-options) section below
4. In case of errors, see [troubleshooting section](troubleshooting.md)
### CLI Commands and Options
The basic syntax of `nym-vpn-cli` is:
```sh
# choose only one conditional --argument listed in {brackets}
sudo ./nym-vpn-cli { --exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY> }
```
To see all the possibilities run with `--help` flag:
```sh
./nym-vpn-cli --help
```
~~~admonish example collapsible=true title="Console output"
```sh
Usage: nym-vpn-cli [OPTIONS] <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
Options:
-c, --config-env-file <CONFIG_ENV_FILE>
Path pointing to an env file describing the network
--mixnet-client-path <MIXNET_CLIENT_PATH>
Path to the data directory of a previously initialised mixnet client, where the keys reside
--entry-gateway-id <ENTRY_GATEWAY_ID>
Mixnet public ID of the entry gateway
--entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
Auto-select entry gateway by country ISO
--entry-gateway-low-latency
Auto-select entry gateway by latency
--exit-router-address <EXIT_ROUTER_ADDRESS>
Mixnet recipient address
--exit-gateway-id <EXIT_GATEWAY_ID>
--exit-gateway-country <EXIT_GATEWAY_COUNTRY>
Mixnet recipient address
--enable-wireguard
Enable the wireguard traffic between the client and the entry gateway
--private-key <PRIVATE_KEY>
Associated private key
--wg-ip <WG_IP>
The IP address of the wireguard interface used for the first hop to the entry gateway
--nym-ipv4 <NYM_IPV4>
The IPv4 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-ipv6 <NYM_IPV6>
The IPv6 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-mtu <NYM_MTU>
The MTU of the nym TUN device that wraps IP packets in sphinx packets
--disable-routing
Disable routing all traffic through the nym TUN device. When the flag is set, the nym TUN device will be created, but to route traffic through it you will need to do it manually, e.g. ping -Itun0
--enable-two-hop
Enable two-hop mixnet traffic. This means that traffic jumps directly from entry gateway to exit gateway
--enable-poisson-rate
Enable Poisson process rate limiting of outbound traffic
--disable-background-cover-traffic
Disable constant rate background loop cover traffic
-h, --help
Print help
-V, --version
Print version
```
~~~
Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.
**Fundamental commands and arguments**
- `--entry-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`)
- `--exit-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`)
- `--exit-router-address`: paste one of the values labeled with a key `"address"` (without `" "`)
- `--enable-wireguard`: Enable the wireguard traffic between the client and the entry gateway. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device
- `--wg-ip`: The address of the wireguard interface, you can get it [here](https://nymvpn.com/en/alpha)
- `--private-key`: get your private key for testing purposes [here](https://nymvpn.com/en/alpha)
- `--enable-two-hop` is a faster setup where the traffic is routed from the client to Entry Gateway and directly to Exit Gateway (default is 5-hops)
**Advanced options**
- `-c` is a path to an enviroment config, like [`sandbox.env`](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env)
- `--enable-poisson`: Enables process rate limiting of outbound traffic (disabled by default). It means that NymVPN client will send packets at a steady stream to the Entry Gateway. By default it's on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.
- `--ip` is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
- `--mtu`: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
- `--disable-routing`: Disable routing all traffic through the VPN TUN device.
## Testnet environment
If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:
1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries:
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
1. Check available Gateways at [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
2. Run with a flag `-c`
```sh
sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
```
In case of errors check out the [troubleshooting](troubleshooting.md) section.
+4 -4
View File
@@ -1,12 +1,12 @@
# NymVPN - Desktop (GUI)
```admonish info
Our alpha testing round is done with participants at live workshop events and the application in this stage may not work for everyone.
Our alpha testing round is done with participants at live workshop events. This guide will not work for everyone, as the NymVPN source code is not yet publicly accessible. The alpha testing is done on Nym testnet Sandbox environment, this configuration is limited and will not work in the future.
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
```
This is a desktop (GUI) version of NymVPN client. A demo of how the application will look like for majority of day-to-day users.
This is the alpha version of NymVPN desktop application (GUI). A demo of how the client will look like for majority of day-to-day users.
Follow the simple [automated script](#automated-script-for-gui-installation) below to install and run NymVPN GUI. If the script didn't work for your distribution or you prefer to do a manual setup follow the steps in the guide for [Linux](gui-linux.md) or [MacOS](gui-mac.md) .
@@ -14,12 +14,12 @@ Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums
## Linux AppImage Automated Installation Method
The latest releases contain `appimage.sh` script. This method makes the installation simple for Linux users who want to run NymVPN from AppImmage. Executing the command below will download the binary to `~/.local/bin` and verify the checksum:
The latest releases contain `appimage.sh` script. This method makes the installation simple for Linux users who want to run NymVPN from AppImmage. Executing the command below will download the binary to `~/.local/bin` and verify the checksum.
```sh
curl -fsSL https://github.com/nymtech/nym-vpn-client/releases/download/nym-vpn-desktop-v<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->/appimage.sh | bash
```
Run with the command:
Run with the command
```sh
sudo -E ~/.local/bin/nym-vpn.appimage
```
+4 -3
View File
@@ -5,15 +5,16 @@
**Nym proudly presents NymVPN alpha** - a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
**You are invited to take part in the alpha testing** of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN [CLI](cli.md) and [GUI](gui.md).
**You are invited to take part in the alpha testing** of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN [CLI](cli.md) and [GUI](gui.md) on the Sandbox testnet environment.
**Here is how**
1. Go to the NymVPN [testers form]({{nym_vpn_form_url}})
2. Fill and submit the [form!]({{nym_vpn_form_url}})
2. Please consent to the GDPR so we can use the results
3. To test the GUI, [go here](gui.md)
4. To test the CLI, [go here](cli.md)
5. Join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers
5. Fill and submit the [form!]({{nym_vpn_form_url}})
6. Join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers
***NymVPN alpha testing will last from 15th of January - 15th of February.***
@@ -2,14 +2,6 @@
Below are listed some points which may need to be addressed when testing NymVPN alpha. If you crashed into any errors which are not listed, please contact us at the testing workshop or in the NymVPN [Matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat).
#### NymVPN attempts to connect to sandbox testnet
If you testing the latest versions and you correctly expect the client to run over the mainnet, but it listens to `https://sandbox-nym-api1.nymtech.net`, it's probably because of your previous configuration.
Check your `config.toml` either in the directory from which you run your client or in `~/.config/nym-vpn/` and remove `sandbox.env` from the config file and folder.
If the problem persists (probably due to some locally cache) download [`mainnet.env`](https://github.com/nymtech/nym/blob/master/envs/mainnet.env) and save it to the same directory.
#### Running GUI failed due to `TOML parse error`
If you see this error when running NymVPN alpha desktop, it's because the older versions needed entry location in `config.toml` configuration file. From `v0.0.3` the entry location is selected directly by the user in the application. This error is due to an old `app-data.toml` config in your computer.
+2 -3
View File
@@ -1,4 +1,3 @@
#
# Summary
[Introduction](introduction.md)
@@ -15,7 +14,7 @@
<!-- - [Version Compatibility Table](binaries/version-compatiblity.md) -->
# Nodes
- [Node Types (Previously Setup Guides)](nodes/overview.md)
- [Node Types (Previously Setup Guides)](nodes/overview.md)
- [Mix Node](nodes/mixnode.md)
- [Gateway](nodes/gateway.md)
- [Network Requester](nodes/network-requester.md)
@@ -57,7 +56,7 @@
- [Mixnet Explorer](explorers/mixnet-explorer.md)
# Nyx Blockchain
- [Interacting with Nyx Chain and Smart Contracts](nyx/interacting-with-chain.md)
- [Interacting with Nyx Chain and Smart Contracts](nyx/interacting-with-chain.md)
- [Smart Contracts](nyx/smart-contracts.md)
- [Mixnet Contract](nyx/mixnet-contract.md)
- [Vesting Contract](nyx/vesting-contract.md)
-6
View File
@@ -1,4 +1,3 @@
#
# Summary
- [Introduction](introduction.md)
@@ -29,11 +28,6 @@
- [ExploreNYM scripts](testing/explorenym-scripts.md)
<!-- - [Run in a Docker](testing/docker-monitor.md) -->
- [Troubleshooting](nodes/troubleshooting.md)
<!--
- [Nym Nodes]()
- [Validators]
- [Binary]
-->
# Token Economics
+9 -64
View File
@@ -7,7 +7,7 @@
## What is the Nym API?
The Nym API is a binary that will be operated by the Nyx validator set. This binary can be run in several different modes, and has two main bits of functionality:
* network monitoring (calculating the routing score of Mixnet nodes)
* generation and validation of [zk-nyms](https://blog.nymtech.net/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet-a3470c9ab10a), our implementation of the Coconut Selective Disclosure Credential Scheme.
* generation and validation of [zk-Nyms](https://blog.nymtech.net/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet-a3470c9ab10a), our implementation of the Coconut Selective Disclosure Credential Scheme.
This is important for both the proper decentralisation of the network uptime calculation and, more pressingly, enabling the NymVPN to utilise privacy preserving payments.
@@ -77,18 +77,18 @@ pruning-interval = "100"
The example value of `100` for `pruning-interval` can be customised as per your requirement.
### Credential Generation
Validators that take part in the DKG ceremony will become part of the 'quorum' generating and verifying zk-nym credentials. These will initially be used for private proof of payment for NymVPN (see our blogposts [here](https://blog.nymtech.net/nymvpn-an-invitation-for-privacy-experts-and-enthusiasts-63644139d09d) and [here](https://blog.nymtech.net/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet-a3470c9ab10a) for more on this), and in the future will be expanded into more general usecases such as [offline ecash](https://arxiv.org/abs/2303.08221).
### (Coming Soon) Credential Generation
Validators that take part in the DKG ceremony will become part of the 'quorum' generating and verifying zk-Nym credentials. These will initially be used for private proof of payment for NymVPN (see our blogposts [here](https://blog.nymtech.net/nymvpn-an-invitation-for-privacy-experts-and-enthusiasts-63644139d09d) and [here](https://blog.nymtech.net/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet-a3470c9ab10a) for more on this), and in the future will be expanded into more general usecases such as [offline ecash](https://arxiv.org/abs/2303.08221).
The DKG ceremony will be used to create a subset of existing validators who run `nym-api` alongside a Nyx full-node. As outlined above, they will be the ones taking part in the generation and verification of zk-nym credentials. The size of the 'minimum viable quorum' is 10 - we are aiming for a larger number than this for the initial quorum in order to have some redundancy in the case of a validator dropping or going offline.
The DKG ceremony will be used to create a subset of existing validators - referred to as the quorum. As outlined above, they will be the ones taking part in the generation and verification of zk-Nym credentials. The size of the 'minimum viable quorum' is 10 - we are aiming for a larger number than this for the initial quorum in order to have some redundancy in the case of a Validator dropping or going offline.
We will be releasing more detailed step-by-step documentation for involved validators nearer to the ceremony itself, but at a high level it will involve:
* the deployment and initialisation of [`group`](https://github.com/nymtech/nym/tree/develop/contracts/multisig/cw4-group) and [`multisig`](https://github.com/nymtech/nym/tree/develop/contracts/multisig) contracts by Nym. Validators that are members of the `group` contract are the only ones that will be able to take part in the ceremony.
* the deployment and initialisation of an instance of the [DKG contract](https://github.com/nymtech/nym/tree/develop/contracts/coconut-dkg) by Nym.
* Validators will update their `nym-api` configs with the address of the deployed contracts. They will also stop running their API instance in caching only mode, instead switching over run with the `--enabled-credentials-mode`.
* From the perspective of operators, this is all they have to do. Under the hood, each `nym-api` instance will then take part in several rounds of key submission, verification, and derivation. This will continue until quorum is acheived.
* From the perspective of operators, this is all they have to do. Under the hood, each `nym-api` instance will then take part in several rounds of key submission, verification, and derivation. This will continue until quorum is acheived. More information on this will be released closer to the time of the ceremony.
**We will be communicating individually with members of the existing validator set who have expressed interest in joining the quorum concerning the timing and specifics of the ceremony**.
**We will be communicating individually with members of the existing Validator set who have expressed interest in joining the quorum concerning the timing and specifics of the ceremony**.
## Current version
```
@@ -117,7 +117,7 @@ You can also check the various arguments required for individual commands with:
./nym-api <COMMAND> --help
```
### Initialising your Nym API Instance in caching mode
### Initialising your Nym API Instance
Initialise your API instance with:
```
@@ -126,70 +126,17 @@ Initialise your API instance with:
You can optionally pass a local identifier for this instance with the `--id` flag. Otherwise the ID of your instance defaults to `default`.
### Enabling credential signing on your Nym API instance
To engage in the Distributed Key Generation (DKG) ceremony, it's essential to transition your `nym-api` instance from its default caching mode to the active credential signing mode. This section guides you through the process of enabling credential signing
#### Generate a new wallet
Begin by generating a new wallet address specifically for your instance to use in credential signing mode. Utilize the `nyxd` command-line tool with the following command:
```
nyxd keys add signer
```
~~~admonish warning title="Backup your keys!"
It's critical to securely back up the mnemonic phrase generated during this process. This mnemonic is your key to recovering the wallet in the future, so store it in a secure, offline location.
~~~
#### Fund the address
Next, deposit NYM tokens into the newly created wallet address to ensure it can cover transaction fees incurred during the credential signing process. `nym-api` will not operate if the wallet's balance falls below 10 NYM tokens, displaying an error message upon startup.
We recommand beginning with an initial deposit of 100 NYM tokens and monitoring the balance regularly, topping it up as necessary to maintain operational readiness.
#### Update API configuration
With your new wallet ready and funded, proceed to update your `nym-api` configuration to enable credential signing:
Update your `config.toml` located in `<HOME_DIR>/.nym/nym-api/foo/config/config.toml` as below:
Enable the coconut signer:
```
[coconut_signer]
# Specifies whether coconut signing protocol is enabled in this process.
enabled = true # This was previously false
```
Set your announce address if it is empty. This is the URL you previously configured for your `nym-api` instance
```
# This is the address you previously configured for the nym-api
# Not to be confused with the Cosmos REST API URL
announce_address = 'https://nym-api.your.tld/'
```
Finally, input the mnemonic phrase generated during the wallet creation step into the mnemonic field
```
mnemonic = '<YOUR_MNEMONIC_HERE>'
```
After completing these steps, your `nym-api` instance is configured to participate in credential signing and the DKG ceremony.
### Running your Nym API Instance
The API binary currently defaults to running in caching mode. You can run your API with:
```
./nym-api run --id <YOUR_ID>
./nym-api run
```
By default the API will be trying to query your full node running locally on `localhost:26657`. If your node is hosted elsewhere, you can specify the RPC location by using the `--nyxd-validator ` flag on `run`:
```
./nym-api run --id <YOUR_ID> --nyxd-validator https://rpc-nym.yourcorp.tld:443
./nym-api run --nyxd-validator https://rpc-nym.yourcorp.tld:443
```
> You can also change the value of `local_validator` in the config file found by default in `$HOME/.nym/nym-api/<ID>/config/config.toml`.
@@ -279,8 +226,6 @@ Starting nym api...
## Automation
You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md) for an example `service` file.
You can also use `nymvisor` to automatically update the `nym-api` node. The steps to install Nymvisor can be found [here](nymvisor-upgrade.md).
## Exposing web endpoint using HTTPS
It is recommended to expose the webserver over HTTPS by using a webserver like Nginx. An example configuration for configuring Nginx is listed [on the maintenance page](maintenance.md#nym-api-configuration). If you're using a custom solution, ensure to allow requests from anywhere by setting a permissive CORS policy.
-3
View File
@@ -1,3 +0,0 @@
# cmdrun scripts
A place for all scripts used for `mdbook-cmdrun` to auto-fill the pages with up todate info, syntax and command outputs.
-182
View File
@@ -1,182 +0,0 @@
import argparse
import os
import requests
import json
import sys
import pandas as pd
from collections import namedtuple
############################################
############## GENERAL FNs #################
############################################
def get_url(args):
config_file = "./api_targets_config.json"
with open(config_file, "r") as f:
config = json.load(f)
env = args.api
endpoint = args.endpoint
if env == "github":
url = f"{config[env]}/{endpoint}"
else:
url = f"{config[env]}/api/v1/{endpoint}"
return url
def subparser_read(args):
url = get_url(args)
r = requests.get(url)
response = r.json()
return response
############################################
########### NYX RELATED FNs ################
############################################
def convert_u_nym(unym):
unym = int(unym)
nym = unym / 1000000
nym = int(nym)
return nym
def thousand_separator(n):
n = f'{n:_}'
return n
def remove_underscore(arg):
string = arg.replace("_", " ")
string = string.title()
return string
def display_supply_table(response, args):
df = pd.DataFrame(response)
df = df.T
del df['denom']
# df.set_axis(['**Item**', '**Amount in NYM**'], axis=1, inplace=True)
df = df.rename_axis('index1').reset_index()
df = df.rename(columns={'index1': '**Item**', 'amount': '**Amount in NYM**'})
df['**Item**'] = df['**Item**'].apply(remove_underscore)
df['**Amount in NYM**'] = df['**Amount in NYM**'].apply(convert_u_nym)
df['**Amount in NYM**'] = df['**Amount in NYM**'].apply(thousand_separator)
table = df.to_markdown(index=False)
print(table)
def read_supply(args):
response = subparser_read(args)
if args.endpoint == "circulating-supply":
if args.format:
display_supply_table(response, args)
else:
print(response)
elif args.endpoint == "foo":
# placeholder for other endpoint args
pass
else:
# placeholder for other endpoint args
pass
###########################################
############ GH RELATED FNs ###############
###########################################
def get_nym_vpn_version(args):
response = subparser_read(args)
if args.client == "desktop":
version = current_desktop_version(args, response)
elif args.client == "cli":
version = current_cli_version(args, response)
else:
print("Incorrect argument for -c, --client")
sys.exit(-1)
def current_cli_version(args, response):
df = pd.DataFrame(response)
print(df)
# NEEDS THIS IN PYTHON:
# current_cli_version=$(curl -s $release_url | jq -r '.[].tag_name' | grep '^nym-vpn-cli-v' | sort -Vr | head -n 1 | awk -F'-v' '{print $NF}')
def current_desktop_version(args, response):
# NEEDS THIS IN PYTHON:
df = pd.DataFrame(response)
print(df)
# version=$(curl -s $release_url | jq -r '.[].tag_name' | grep '^nym-vpn-desktop-v' | sort -Vr | head -n 1 | awk -F'-v' '{print $NF}')
###########################################
############### MAIN PARSER ###############
###########################################
def parser_main():
parser = argparse.ArgumentParser(
prog="Nym API scraper",
description='''Get any live data from Nyx validator''',
epilog=''
)
subparsers = parser.add_subparsers(help="")
parser_supply = subparsers.add_parser('supply',
help='reads API on supply',
aliases=['s','S']
)
parser_supply.add_argument(
"-a","--api",
type=str,
default="mainnet",
help="choose: mainnet, perf, sandbox"
)
parser_supply.add_argument(
"-e","--endpoint",
type=str,
help="choose from: https://validator.nymtech.net/api/swagger/index.html"
)
parser_supply.add_argument(
"-f","--format",
action="store_true",
help="format the output for documentation purpose (.md) - default: False (raw output)",
)
parser_supply.set_defaults(func=read_supply)
parser_nym_vpn = subparsers.add_parser('nym_vpn',
help='reads NymVPN latest version',
aliases=['n','N']
)
parser_nym_vpn.add_argument(
"-c","--client",
type=str,
default="desktop",
help="choose: desktop, cli - default: desktop"
)
parser_nym_vpn.add_argument(
"-a","--api",
type=str,
default="github",
help="choose: mainnet, perf, sandbox"
)
parser_nym_vpn.add_argument(
"-e","--endpoint",
type=str,
help="add the url suffix",
default="repos/nymtech/nym-vpn-client/releases"
)
parser_nym_vpn.set_defaults(func=get_nym_vpn_version)
args = parser.parse_args()
try:
args.func(args)
except AttributeError as e:
print("Error on argparser")
sys.exit(-1)
if __name__ == "__main__":
parser_main()
@@ -1,6 +0,0 @@
{
"sandbox": "https://sandbox-nym-api1.nymtech.net",
"perf": "https://api.performance.nymte.ch",
"mainnet": "https://validator.nymtech.net",
"github": "https://api.github.com"
}
+4 -4
View File
@@ -13,10 +13,10 @@ DENOMS_EXPONENT=6
REWARDING_VALIDATOR_ADDRESS=n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa
MIXNET_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav
VESTING_CONTRACT_ADDRESS=n1unyuj8qnmygvzuex3dwmg9yzt9alhvyeat0uu0jedg2wj33efl5qackslz
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n1ljlwey4xdj0zs7zueepc48nkr033fca6fjgvurfvttqegm8dvsrswsul70
GROUP_CONTRACT_ADDRESS=n10v3rjnq4cjyccfykyams68ztce337gksuu6f0lvtl4meuwvkewaqru4uav
MULTISIG_CONTRACT_ADDRESS=n1cemnu8as0ls45v3caunpesl8jlsfw2ff9rlwnltlecp7zrxct4dsqc2y42
COCONUT_DKG_CONTRACT_ADDRESS=n1zx96qgd88vqlzcxkpwzks7kqs5ctrx36xtzfc58p7q6c4ng9anlqzc4nh8
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n13902g92xfefeyzuyed49snlm5fxv5ms6mdq5kvrut27hasdw5a9q9vyw6c
GROUP_CONTRACT_ADDRESS=n18nczmqw6adwxg2wnlef3hf0etf8anccafp2pjpul5rrtmv96umyq5mv7t5
MULTISIG_CONTRACT_ADDRESS=n1q3zzxl78rlmxv3vn0uf4vkyz285lk8q2xzne299yt9x6mpfgk90qukuzmv
COCONUT_DKG_CONTRACT_ADDRESS=n1jsz20ggp5a6v76j060erkzvxmeus8htlpl77yxp878f0gf95cyaq6p2pee
NAME_SERVICE_CONTRACT_ADDRESS=n12ne7qtmdwd0j03t9t5es8md66wq4e5xg9neladrsag8fx3y89rcs36asfp
SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS=n1ps5yutd7sufwg058qd7ac7ldnlazsvmhzqwucsfxmm445d70u8asqxpur4
EPHEMERA_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "explorer-api"
version = "1.1.34"
version = "1.1.33"
edition = "2021"
license.workspace = true
@@ -10,7 +10,7 @@ license.workspace = true
chrono = { version = "0.4.31", features = ["serde"] }
clap = { workspace = true, features = ["cargo", "derive"] }
dotenvy = { workspace = true }
humantime-serde = { workspace = true }
humantime-serde = "1.0"
isocountry = "0.3.2"
itertools = "0.10.3"
log = { workspace = true }
+1 -1
View File
@@ -3,4 +3,4 @@ NYM_API_URL=https://validator.nymtech.net
VALIDATOR_URL=https://rpc.nymtech.net
BIG_DIPPER_URL=https://blocks.nymtech.net
CURRENCY_DENOM=unym
CURRENCY_STAKING_DENOM=unyx
CURRENCY_STAKING_DENOM=unyx
+1 -22
View File
@@ -6,9 +6,6 @@
"scripts": {
"start": "webpack serve --progress --port 3000",
"build": "webpack build --progress --config webpack.prod.js",
"ci:dev": "echo 'Building CI for branch preview...' && yarn --cwd .. build && cp .env.dev .env && yarn build",
"ci:prod": "echo 'Building CI for prod preview...' && yarn --cwd .. build && cp .env.prod .env && yarn build",
"ci": "[ \"$CI_PROD\" = true ] && yarn ci:prod || yarn ci:dev",
"build:serve": "npx serve dist",
"test": "jest",
"test:watch": "jest --watch",
@@ -21,40 +18,22 @@
"storybook:build": "build-storybook"
},
"dependencies": {
"@cosmjs/cosmwasm-stargate": "^0.32.0",
"@cosmjs/crypto": "^0.32.0",
"@cosmjs/encoding": "^0.32.0",
"@cosmjs/math": "^0.26.2",
"@cosmjs/stargate": "^0.32.0",
"@cosmjs/tendermint-rpc": "^0.32.0",
"@cosmos-kit/core": "^2.8.9",
"@cosmos-kit/keplr-extension": "^2.7.9",
"@cosmos-kit/react": "^2.10.10",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@interchain-ui/react": "^1.14.2",
"@mui/icons-material": "^5.0.0",
"@mui/material": "^5.0.1",
"@mui/styles": "^5.0.1",
"@mui/system": "^5.0.1",
"@mui/x-data-grid": "^5.0.0-beta.5",
"@nymproject/contract-clients": "1.2.4-rc.1",
"@nymproject/mui-theme": "^1.0.0",
"@nymproject/node-tester": "^1.0.0",
"@nymproject/nym-validator-client": "^0.18.0",
"@nymproject/react": "^1.0.0",
"@nymproject/types": "^1.0.0",
"@tauri-apps/api": "^1.5.1",
"big.js": "^6.2.1",
"bs58": "^5.0.0",
"buffer": "^6.0.3",
"chain-registry": "^1.29.1",
"@chain-registry/types": "^0.18.1",
"cosmjs-types": "^0.9.0",
"d3-scale": "^4.0.0",
"date-fns": "^2.24.0",
"i18n-iso-countries": "^6.8.0",
"lodash": "^4.17.21",
"i18n-iso-countries": "^6.8.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4",
+1 -6
View File
@@ -1,7 +1,7 @@
// master APIs
export const API_BASE_URL = process.env.EXPLORER_API_URL;
export const NYM_API_BASE_URL = process.env.NYM_API_URL;
export const VALIDATOR_BASE_URL = process.env.VALIDATOR_URL || 'https://rpc.nymtech.net';
export const VALIDATOR_BASE_URL = process.env.VALIDATOR_URL;
export const BIG_DIPPER = process.env.BIG_DIPPER_URL;
// specific API routes
@@ -24,8 +24,3 @@ export const MIXNODE_API_ERROR = "We're having trouble finding that record, plea
export const NYM_WEBSITE = 'https://nymtech.net';
export const NYM_BIG_DIPPER = 'https://mixnet.explorers.guru';
export const NYM_MIXNET_CONTRACT =
process.env.NYM_MIXNET_CONTRACT || 'n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr';
export const COSMOS_KIT_USE_CHAIN = process.env.COSMOS_KIT_USE_CHAIN || 'sandbox';
export const WALLET_CONNECT_PROJECT_ID = process.env.WALLET_CONNECT_PROJECT_ID || '';
@@ -1,83 +0,0 @@
import React from 'react';
import {
Breakpoint,
Button,
Paper,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
SxProps,
Typography,
} from '@mui/material';
export interface ConfirmationModalProps {
open: boolean;
onConfirm: () => void;
onClose?: () => void;
children?: React.ReactNode;
title: React.ReactNode | string;
subTitle?: React.ReactNode | string;
confirmButton: React.ReactNode | string;
disabled?: boolean;
sx?: SxProps;
fullWidth?: boolean;
maxWidth?: Breakpoint;
backdropProps?: object;
}
export const ConfirmationModal = ({
open,
onConfirm,
onClose,
children,
title,
subTitle,
confirmButton,
disabled,
sx,
fullWidth,
maxWidth,
backdropProps,
}: ConfirmationModalProps) => {
const Title = (
<DialogTitle id="responsive-dialog-title" sx={{ pb: 2 }}>
{title}
{subTitle &&
(typeof subTitle === 'string' ? (
<Typography fontWeight={400} variant="subtitle1" fontSize={12} color="grey">
{subTitle}
</Typography>
) : (
subTitle
))}
</DialogTitle>
);
const ConfirmButton =
typeof confirmButton === 'string' ? (
<Button onClick={onConfirm} variant="contained" fullWidth disabled={disabled} sx={{ py: 1.6 }}>
<Typography variant="button" fontSize="large">
{confirmButton}
</Typography>
</Button>
) : (
confirmButton
);
return (
<Dialog
open={open}
onClose={onClose}
aria-labelledby="responsive-dialog-title"
maxWidth={maxWidth || 'sm'}
sx={{ textAlign: 'center', ...sx }}
fullWidth={fullWidth}
BackdropProps={backdropProps}
PaperComponent={Paper}
PaperProps={{ elevation: 0 }}
>
{Title}
<DialogContent>{children}</DialogContent>
<DialogActions sx={{ px: 3, pb: 3 }}>{ConfirmButton}</DialogActions>
</Dialog>
);
};
@@ -1,33 +0,0 @@
import * as React from 'react';
import { Button, IconButton } from '@mui/material';
import { SxProps } from '@mui/system';
import { useIsMobile } from '@src/hooks';
import { DelegateIcon } from '@src/icons/DelevateSVG';
export const DelegateIconButton: FCWithChildren<{
size?: 'small' | 'medium';
disabled?: boolean;
tooltip?: React.ReactNode;
sx?: SxProps;
onDelegate: () => void;
}> = ({ onDelegate, sx, disabled, size = 'medium' }) => {
const isMobile = useIsMobile();
const handleOnDelegate = () => {
onDelegate();
};
if (isMobile) {
return (
<IconButton size="small" disabled={disabled} onClick={handleOnDelegate}>
<DelegateIcon fontSize="small" />
</IconButton>
);
}
return (
<Button variant="outlined" size={size} disabled={disabled} onClick={handleOnDelegate} sx={sx}>
Delegate
</Button>
);
};
@@ -1,166 +0,0 @@
import React, { useState } from 'react';
import { Box, SxProps } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
import { CurrencyDenom, DecCoin } from '@nymproject/types';
import { useWalletContext } from '@src/context/wallet';
import { useDelegationsContext } from '@src/context/delegations';
import { SimpleModal } from './SimpleModal';
import { ModalListItem } from './ModalListItem';
import { DelegationModalProps } from './DelegationModal';
import { validateAmount } from '../../utils/currency';
import { urls } from '../../utils';
const MIN_AMOUNT_TO_DELEGATE = 10;
export const DelegateModal: FCWithChildren<{
mixId: number;
identityKey: string;
header?: string;
buttonText?: string;
rewardInterval?: string;
estimatedReward?: number;
profitMarginPercentage?: string | null;
nodeUptimePercentage?: number | null;
denom: CurrencyDenom;
sx?: SxProps;
backdropProps?: object;
onClose: () => void;
onOk?: (delegationModalProps: DelegationModalProps) => void;
}> = ({ mixId, identityKey, onClose, onOk, denom, sx }) => {
const [amount, setAmount] = useState<DecCoin | undefined>({ amount: '10', denom: 'nym' });
const [isValidated, setValidated] = useState<boolean>(false);
const [errorAmount, setErrorAmount] = useState<string | undefined>();
const { address, balance } = useWalletContext();
const { handleDelegate } = useDelegationsContext();
const validate = async () => {
let newValidatedValue = true;
let errorAmountMessage;
if (amount && !(await validateAmount(amount.amount, '0'))) {
newValidatedValue = false;
errorAmountMessage = 'Please enter a valid amount';
}
if (amount && +amount.amount < MIN_AMOUNT_TO_DELEGATE) {
errorAmountMessage = `Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${denom.toUpperCase()}`;
newValidatedValue = false;
}
if (!amount?.amount.length) {
newValidatedValue = false;
}
if (amount && balance.data && +balance.data - +amount.amount <= 0) {
errorAmountMessage = 'Not enough funds';
newValidatedValue = false;
}
setErrorAmount(errorAmountMessage);
setValidated(newValidatedValue);
};
const delegateToMixnode = async ({
delegationMixId,
delegationAmount,
}: {
delegationMixId: number;
delegationAmount: string;
}) => {
try {
const tx = await handleDelegate(delegationMixId, delegationAmount);
return tx;
} catch (e) {
console.error('Failed to delegate to mixnode', e);
throw e;
}
};
const handleConfirm = async () => {
if (mixId && amount && onOk) {
onOk({
status: 'loading',
});
try {
if (!address) {
throw new Error('Please connect your wallet');
}
const tx = await delegateToMixnode({
delegationMixId: mixId,
delegationAmount: amount.amount,
});
if (!tx) {
throw new Error('Failed to delegate');
}
onOk({
status: 'success',
message: 'Delegation can take up to one hour to process',
transactions: [
{ url: `${urls('MAINNET').blockExplorer}/transaction/${tx.transactionHash}`, hash: tx.transactionHash },
],
});
} catch (e) {
console.error('Failed to delegate', e);
onOk({
status: 'error',
message: (e as Error).message,
});
}
}
};
const handleAmountChanged = (newAmount: DecCoin) => {
setAmount(newAmount);
};
React.useEffect(() => {
validate();
}, [amount, identityKey, mixId]);
return (
<SimpleModal
open
onClose={onClose}
onOk={handleConfirm}
header="Delegate"
okLabel="Delegate"
okDisabled={!isValidated}
sx={sx}
>
<Box sx={{ mt: 3 }} gap={2}>
<IdentityKeyFormField
required
fullWidth
label="Node identity key"
onChanged={() => undefined}
initialValue={identityKey}
readOnly
showTickOnValid={false}
/>
</Box>
<Box display="flex" gap={2} alignItems="center" sx={{ mt: 3 }}>
<CurrencyFormField
required
fullWidth
autoFocus
label="Amount"
initialValue={amount?.amount || '10'}
onChanged={handleAmountChanged}
denom={denom}
validationError={errorAmount}
/>
</Box>
<Box sx={{ mt: 3 }}>
<ModalListItem label="Account balance" value={`${balance.data} NYM`} divider fontWeight={600} />
</Box>
<ModalListItem label="Est. fee for this transaction will be calculated in your connected wallet" />
</SimpleModal>
);
};
@@ -1,67 +0,0 @@
import React from 'react';
import { Typography, SxProps, Stack } from '@mui/material';
import { Link } from '@nymproject/react/link/Link';
import { LoadingModal } from './LoadingModal';
import { ConfirmationModal } from './ConfirmationModal';
import { ErrorModal } from './ErrorModal';
export type DelegationModalProps = {
status: 'loading' | 'success' | 'error' | 'info';
message?: string;
transactions?: {
url: string;
hash: string;
}[];
};
export const DelegationModal: FCWithChildren<
DelegationModalProps & {
open: boolean;
onClose: () => void;
sx?: SxProps;
backdropProps?: object;
children?: React.ReactNode;
}
> = ({ status, message, transactions, open, onClose, children, sx, backdropProps }) => {
if (status === 'loading') return <LoadingModal sx={sx} backdropProps={backdropProps} />;
if (status === 'error') {
return (
<ErrorModal message={message} sx={sx} open={open} onClose={onClose}>
{children}
</ErrorModal>
);
}
if (status === 'info') {
return (
<ConfirmationModal open={open} title="Connect wallet" confirmButton="OK" onConfirm={onClose}>
<Typography>{message}</Typography>
</ConfirmationModal>
);
}
return (
<ConfirmationModal
open={open}
onConfirm={onClose || (() => {})}
title="Transaction successful"
confirmButton="Done"
>
<Stack alignItems="center" spacing={2} mb={0}>
{message && <Typography>{message}</Typography>}
{transactions?.length === 1 && (
<Link href={transactions[0].url} target="_blank" sx={{ ml: 1 }} text="View on blockchain" noIcon />
)}
{transactions && transactions.length > 1 && (
<Stack alignItems="center" spacing={1}>
<Typography>View the transactions on blockchain:</Typography>
{transactions.map(({ url, hash }) => (
<Link href={url} target="_blank" sx={{ ml: 1 }} text={hash.slice(0, 6)} key={hash} noIcon />
))}
</Stack>
)}
</Stack>
</ConfirmationModal>
);
};
@@ -1,28 +0,0 @@
import React from 'react';
import { Box, Button, Modal, SxProps, Typography } from '@mui/material';
import { modalStyle } from './SimpleModal';
export const ErrorModal: FCWithChildren<{
open: boolean;
title?: string;
message?: string;
sx?: SxProps;
backdropProps?: object;
onClose: () => void;
children?: React.ReactNode;
}> = ({ children, open, title, message, sx, backdropProps, onClose }) => (
<Modal open={open} onClose={onClose} BackdropProps={backdropProps}>
<Box sx={{ ...modalStyle(), ...sx }} textAlign="center">
<Typography color={(theme) => theme.palette.error.main} mb={1}>
{title || 'Oh no! Something went wrong...'}
</Typography>
<Typography my={5} color="text.primary" sx={{ textOverflow: 'wrap', overflowWrap: 'break-word' }}>
{message}
</Typography>
{children}
<Button variant="contained" onClick={onClose}>
Close
</Button>
</Box>
</Modal>
);
@@ -1,18 +0,0 @@
import React from 'react';
import { Box, CircularProgress, Modal, Stack, Typography, SxProps } from '@mui/material';
import { modalStyle } from './SimpleModal';
export const LoadingModal: FCWithChildren<{
text?: string;
sx?: SxProps;
backdropProps?: object;
}> = ({ sx, text = 'Please wait...' }) => (
<Modal open>
<Box sx={{ ...modalStyle(), ...sx }} textAlign="center">
<Stack spacing={4} direction="row" alignItems="center">
<CircularProgress />
<Typography sx={{ color: 'text.primary' }}>{text}</Typography>
</Stack>
</Box>
</Modal>
);
@@ -1,6 +0,0 @@
import React from 'react';
import { Box, SxProps } from '@mui/material';
export const ModalDivider: FCWithChildren<{
sx?: SxProps;
}> = ({ sx }) => <Box borderTop="1px solid" borderColor="rgba(141, 147, 153, 0.2)" my={1} sx={sx} />;
@@ -1,32 +0,0 @@
import React from 'react';
import { Box, Stack, SxProps, Typography, TypographyProps } from '@mui/material';
import { ModalDivider } from './ModalDivider';
export const ModalListItem: FCWithChildren<{
label: string;
divider?: boolean;
hidden?: boolean;
fontWeight?: TypographyProps['fontWeight'];
fontSize?: TypographyProps['fontSize'];
light?: boolean;
value?: React.ReactNode;
sxValue?: SxProps;
}> = ({ label, value, hidden, fontWeight, fontSize, divider, sxValue }) => (
<Box sx={{ display: hidden ? 'none' : 'block' }}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography fontSize="smaller" fontWeight={fontWeight} sx={{ color: 'text.primary', fontSize: 14 }}>
{label}
</Typography>
{value && (
<Typography
fontSize="smaller"
fontWeight={fontWeight}
sx={{ color: 'text.primary', fontSize: fontSize || 14, ...sxValue }}
>
{value}
</Typography>
)}
</Stack>
{divider && <ModalDivider />}
</Box>
);
@@ -1,112 +0,0 @@
import React from 'react';
import { Box, Button, Modal, Stack, SxProps, Typography } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import ErrorOutline from '@mui/icons-material/ErrorOutline';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
import { useIsMobile } from '../../hooks/useIsMobile';
export const modalStyle = (width: number | string = 600) => ({
position: 'absolute' as 'absolute',
top: '50%',
left: '50%',
width,
transform: 'translate(-50%, -50%)',
bgcolor: 'background.paper',
boxShadow: 24,
borderRadius: '16px',
p: 4,
});
export const StyledBackButton = ({
onBack,
label,
fullWidth,
sx,
}: {
onBack: () => void;
label?: string;
fullWidth?: boolean;
sx?: SxProps;
}) => (
<Button disableFocusRipple size="large" fullWidth={fullWidth} variant="outlined" onClick={onBack} sx={sx}>
{label || <ArrowBackIosNewIcon fontSize="small" />}
</Button>
);
export const SimpleModal: FCWithChildren<{
open: boolean;
hideCloseIcon?: boolean;
displayErrorIcon?: boolean;
displayInfoIcon?: boolean;
headerStyles?: SxProps;
subHeaderStyles?: SxProps;
buttonFullWidth?: boolean;
onClose?: () => void;
onOk?: () => Promise<void>;
onBack?: () => void;
header: string | React.ReactNode;
subHeader?: string;
okLabel: string;
backLabel?: string;
backButtonFullWidth?: boolean;
okDisabled?: boolean;
sx?: SxProps;
children?: React.ReactNode;
}> = ({
open,
hideCloseIcon,
displayErrorIcon,
displayInfoIcon,
headerStyles,
buttonFullWidth,
onClose,
okDisabled,
onOk,
onBack,
header,
subHeader,
okLabel,
backLabel,
backButtonFullWidth,
sx,
children,
}) => {
const isMobile = useIsMobile();
return (
<Modal open={open} onClose={onClose}>
<Box sx={{ ...modalStyle(isMobile ? '90%' : 600), ...sx }}>
{displayErrorIcon && <ErrorOutline color="error" sx={{ mb: 3 }} />}
{displayInfoIcon && <InfoOutlinedIcon sx={{ mb: 2, color: 'blue' }} />}
<Stack direction="row" justifyContent="space-between" alignItems="center">
{typeof header === 'string' ? (
<Typography fontSize={20} fontWeight={600} sx={{ color: 'text.primary', ...headerStyles }}>
{header}
</Typography>
) : (
header
)}
{!hideCloseIcon && <CloseIcon onClick={onClose} cursor="pointer" />}
</Stack>
<Typography mt={subHeader ? 0.5 : 0} mb={3} fontSize={12} color={(theme) => theme.palette.text.secondary}>
{subHeader}
</Typography>
{children}
{(onOk || onBack) && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mt: 2, width: buttonFullWidth ? '100%' : null }}>
{onBack && <StyledBackButton onBack={onBack} label={backLabel} fullWidth={backButtonFullWidth} />}
{onOk && (
<Button variant="contained" fullWidth size="large" onClick={onOk} disabled={okDisabled}>
{okLabel}
</Button>
)}
</Box>
)}
</Box>
</Modal>
);
};
@@ -1,10 +0,0 @@
export * from './ConfirmationModal';
export * from './DelegateIconButton';
export * from './DelegationModal';
export * from './DelegateModal';
export * from './ErrorModal';
export * from './LoadingModal';
export * from './ModalDivider';
export * from './ModalListItem';
export * from './SimpleModal';
export * from './styles';
@@ -1,21 +0,0 @@
import { Theme } from '@mui/material/styles';
export const backDropStyles = (theme: Theme) => {
const { mode } = theme.palette;
return {
style: {
left: mode === 'light' ? '0' : '50%',
width: '50%',
},
};
};
export const modalStyles = (theme: Theme) => {
const { mode } = theme.palette;
return { left: mode === 'light' ? '25%' : '75%' };
};
export const dialogStyles = (theme: Theme) => {
const { mode } = theme.palette;
return { left: mode === 'light' ? '-50%' : '50%' };
};
+2
View File
@@ -14,6 +14,7 @@ import { useTheme } from '@mui/material/styles';
import { Tooltip } from '@nymproject/react/tooltip/Tooltip';
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard';
import { Box } from '@mui/system';
import { cellStyles } from './Universal-DataGrid';
import { unymToNym } from '../utils/currency';
import { GatewayEnrichedRowType } from './Gateways';
import { MixnodeRowType } from './MixNodes';
@@ -109,6 +110,7 @@ export const DetailTable: FCWithChildren<{
scope="row"
variant="body"
sx={{
...cellStyles,
padding: 2,
width: 200,
fontSize: 14,

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