Compare commits
141 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 589ee64516 | |||
| b20ab5dc50 | |||
| 5bdff28a11 | |||
| 4795a643a4 | |||
| f7f6421415 | |||
| 891cfb80ea | |||
| 9344296804 | |||
| 3538b5237e | |||
| 5581f735d2 | |||
| c0ede6a506 | |||
| 5d6b84a94f | |||
| 66fff0edf0 | |||
| 2bdb623101 | |||
| 1f435880d7 | |||
| 34579222c5 | |||
| 2a43134327 | |||
| 844bcba6e8 | |||
| f3ac17eb9d | |||
| 6296d09adf | |||
| 2ae81f6da0 | |||
| 1d5e8b62ac | |||
| 581cdd5bdf | |||
| e2e49e7136 | |||
| dff82f946f | |||
| ec61728654 | |||
| 61471e9058 | |||
| ed4fd84503 | |||
| cb4b0403b5 | |||
| da8e513627 | |||
| 3f6de8b10c | |||
| 1e01a8e633 | |||
| aaf3dca5b9 | |||
| f939cae3d9 | |||
| 1db61f800c | |||
| 5096c1e60e | |||
| 7e36595d8f | |||
| 515aedac60 | |||
| dca2b2c763 | |||
| c92f09543e | |||
| b45eb16783 | |||
| f8523dc7d1 | |||
| 996ce6a233 | |||
| 1dcb0a0456 | |||
| 55b99e4ce1 | |||
| bd94dd3055 | |||
| 0d19bb4ddc | |||
| dcd70155cd | |||
| a469aeff05 | |||
| 107199bd9c | |||
| 53524447c4 | |||
| bc832c97d8 | |||
| 4989d47ea2 | |||
| 3cb69780a6 | |||
| 68b61bfa84 | |||
| 06fca9bd1f | |||
| 4c10cebf1b | |||
| aea962b546 | |||
| ab2a1c3fe5 | |||
| 8d0c040015 | |||
| 42efff83da | |||
| 86fe955592 | |||
| c3ce0d0b5c | |||
| 0e2cfa5be0 | |||
| 17a5872c6d | |||
| 969155bf91 | |||
| f4fafbfea5 | |||
| 5e97b1f79a | |||
| b52bf951a6 | |||
| 98805a11e4 | |||
| 0a2f28b0ec | |||
| db1ad4dcab | |||
| 78ca539018 | |||
| 04cafc72dc | |||
| 63812994a1 | |||
| 19dee11539 | |||
| 6f3a6b7855 | |||
| 7c84ad4384 | |||
| bc647fc8e2 | |||
| 429ff6045d | |||
| 0de1deced4 | |||
| fc2eedfc66 | |||
| 7ddd819ff3 | |||
| 83b416d12d | |||
| b9c775c3ae | |||
| b613cf87c8 | |||
| 6f669866e9 | |||
| 4e61fefec8 | |||
| b4514ecd83 | |||
| 4f6902525e | |||
| 881139e36f | |||
| 32e2557456 | |||
| 8b44820e51 | |||
| 5e6417f837 | |||
| 3d5ac0b883 | |||
| dfb2a2f380 | |||
| d1de751850 | |||
| ecee6ca863 | |||
| 31ea3f92e2 | |||
| f19c934fae | |||
| 10d6f20de7 | |||
| 96b33bfbe4 | |||
| 444c787d0a | |||
| 61fcd4ac69 | |||
| b76802e6eb | |||
| 7d351029a4 | |||
| 4ee445c119 | |||
| 61ddeea495 | |||
| 7b802033b3 | |||
| b484f47369 | |||
| 66979df10c | |||
| 82f161fb91 | |||
| 9d0fd681d4 | |||
| c2ab47a102 | |||
| 8704c21621 | |||
| 03ffb25bf9 | |||
| 70db1ad062 | |||
| 952ed9b642 | |||
| f57fe79686 | |||
| 9179f1c351 | |||
| c4f7a1e09d | |||
| 701012a968 | |||
| 9767f72b8f | |||
| de0fb7459d | |||
| e2ead6dbe1 | |||
| 7b10d92ca4 | |||
| 2c6e5eb673 | |||
| 02fde4e530 | |||
| cc25fc1f32 | |||
| c971e486b5 | |||
| 96a9eb6f6a | |||
| 9eeb61ea0a | |||
| 08042c61ad | |||
| 36c74f30e5 | |||
| 4956d13bdc | |||
| d9f6c0723e | |||
| 52f5656190 | |||
| 21cd90f238 | |||
| 72e243042e | |||
| c2ad4e5bb4 | |||
| 5f7f5ef92d | |||
| 008afe7a85 |
@@ -8,11 +8,6 @@ on:
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
enable_wireguard:
|
||||
description: "Add --features wireguard"
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
enable_deb:
|
||||
description: "True to enable cargo-deb installation and .deb package building"
|
||||
required: false
|
||||
@@ -70,9 +65,6 @@ jobs:
|
||||
- name: Set CARGO_FEATURES
|
||||
run: |
|
||||
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
|
||||
if: >
|
||||
github.event_name == 'schedule' ||
|
||||
(github.event_name == 'workflow_dispatch' && inputs.enable_wireguard == true)
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
||||
@@ -51,6 +51,10 @@ jobs:
|
||||
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
|
||||
|
||||
- name: Set CARGO_FEATURES
|
||||
run: |
|
||||
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -60,8 +64,8 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release
|
||||
|
||||
args: --workspace --release ${{ env.CARGO_FEATURES }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
||||
+38
-1
@@ -4,6 +4,44 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.9-topdeck] (2024-07-26)
|
||||
|
||||
- chore: fix 1.80 lint issues ([#4731])
|
||||
- Handle clients with different versions in IPR ([#4723])
|
||||
- Add 1GB/day/user bandwidth cap ([#4717])
|
||||
- Feature/merge back ([#4710])
|
||||
- removed mixnode/gateway config migration code and disabled cli without explicit flag ([#4706])
|
||||
|
||||
[#4731]: https://github.com/nymtech/nym/pull/4731
|
||||
[#4723]: https://github.com/nymtech/nym/pull/4723
|
||||
[#4717]: https://github.com/nymtech/nym/pull/4717
|
||||
[#4710]: https://github.com/nymtech/nym/pull/4710
|
||||
[#4706]: https://github.com/nymtech/nym/pull/4706
|
||||
|
||||
## [2024.8-wispa] (2024-07-10)
|
||||
|
||||
- add event parsing to support cosmos_sdk > 0.50 ([#4697])
|
||||
- Fix NR config compatibility ([#4690])
|
||||
- Remove UserAgent constructor since it's weakly typed ([#4689])
|
||||
- [bugfix]: Node_api_check CLI looked over roles on blacklisted nodes ([#4687])
|
||||
- Add mixnodes to self describing api cache ([#4684])
|
||||
- Move and whole bump of crates to workspace and upgrade some ([#4680])
|
||||
- Remove code that refers to removed nym-network-statistics ([#4679])
|
||||
- Remove nym-network-statistics ([#4678])
|
||||
- Create UserAgent that can be passed from the binary to the nym api client ([#4677])
|
||||
- Add authenticator ([#4667])
|
||||
|
||||
[#4697]: https://github.com/nymtech/nym/pull/4697
|
||||
[#4690]: https://github.com/nymtech/nym/pull/4690
|
||||
[#4689]: https://github.com/nymtech/nym/pull/4689
|
||||
[#4687]: https://github.com/nymtech/nym/pull/4687
|
||||
[#4684]: https://github.com/nymtech/nym/pull/4684
|
||||
[#4680]: https://github.com/nymtech/nym/pull/4680
|
||||
[#4679]: https://github.com/nymtech/nym/pull/4679
|
||||
[#4678]: https://github.com/nymtech/nym/pull/4678
|
||||
[#4677]: https://github.com/nymtech/nym/pull/4677
|
||||
[#4667]: https://github.com/nymtech/nym/pull/4667
|
||||
|
||||
## [2024.7-doubledecker] (2024-07-04)
|
||||
|
||||
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
|
||||
@@ -513,7 +551,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#3187]: https://github.com/nymtech/nym/issues/3187
|
||||
[#3203]: https://github.com/nymtech/nym/pull/3203
|
||||
[#3199]: https://github.com/nymtech/nym/pull/3199
|
||||
>>>>>>> master
|
||||
|
||||
## [v1.1.13] (2023-03-15)
|
||||
|
||||
|
||||
Generated
+70
-31
@@ -1471,7 +1471,7 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"parking_lot 0.12.3",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
@@ -1487,7 +1487,7 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"parking_lot 0.12.3",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
@@ -2240,7 +2240,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.36"
|
||||
version = "1.1.38"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.5.7",
|
||||
@@ -3933,6 +3933,18 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.9",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mix-fetch-wasm"
|
||||
version = "1.3.0-rc.0"
|
||||
@@ -4114,7 +4126,7 @@ dependencies = [
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
@@ -4192,7 +4204,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.40"
|
||||
version = "1.1.42"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4282,10 +4294,10 @@ dependencies = [
|
||||
"nym-ecash-time",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-node-requests",
|
||||
"nym-serde-helpers",
|
||||
"rocket",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde-helpers",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"tendermint 0.37.0",
|
||||
@@ -4313,6 +4325,7 @@ dependencies = [
|
||||
"bs58 0.5.1",
|
||||
"bytes",
|
||||
"clap 4.5.7",
|
||||
"defguard_wireguard_rs",
|
||||
"fastrand 2.1.0",
|
||||
"futures",
|
||||
"ipnetwork 0.16.0",
|
||||
@@ -4412,7 +4425,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.38"
|
||||
version = "1.1.40"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -4491,7 +4504,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.37"
|
||||
version = "1.1.39"
|
||||
dependencies = [
|
||||
"bs58 0.5.1",
|
||||
"clap 4.5.7",
|
||||
@@ -4550,6 +4563,7 @@ dependencies = [
|
||||
"nym-config",
|
||||
"nym-country-group",
|
||||
"nym-credential-storage",
|
||||
"nym-credentials-interface",
|
||||
"nym-crypto",
|
||||
"nym-ecash-time",
|
||||
"nym-explorer-client",
|
||||
@@ -4796,10 +4810,10 @@ dependencies = [
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
"nym-client-core",
|
||||
"nym-compact-ecash",
|
||||
"nym-config",
|
||||
"nym-credential-storage",
|
||||
"nym-credentials",
|
||||
"nym-credentials-interface",
|
||||
"nym-ecash-time",
|
||||
"nym-validator-client",
|
||||
"thiserror",
|
||||
@@ -4836,8 +4850,10 @@ dependencies = [
|
||||
"bls12_381",
|
||||
"nym-compact-ecash",
|
||||
"nym-ecash-time",
|
||||
"nym-network-defaults",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"strum 0.25.0",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
@@ -4997,6 +5013,7 @@ dependencies = [
|
||||
"nym-ecash-contract-common",
|
||||
"nym-ecash-double-spending",
|
||||
"nym-gateway-requests",
|
||||
"nym-gateway-storage",
|
||||
"nym-ip-packet-router",
|
||||
"nym-mixnet-client",
|
||||
"nym-mixnode-common",
|
||||
@@ -5086,6 +5103,24 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway-storage"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"defguard_wireguard_rs",
|
||||
"log",
|
||||
"nym-credentials-interface",
|
||||
"nym-gateway-requests",
|
||||
"nym-sphinx",
|
||||
"sqlx",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-group-contract-common"
|
||||
version = "0.1.0"
|
||||
@@ -5377,7 +5412,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.38"
|
||||
version = "1.1.40"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -5428,7 +5463,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.1.4"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bip39",
|
||||
@@ -5648,6 +5683,7 @@ dependencies = [
|
||||
"nym-credential-storage",
|
||||
"nym-credential-utils",
|
||||
"nym-credentials",
|
||||
"nym-credentials-interface",
|
||||
"nym-crypto",
|
||||
"nym-gateway-requests",
|
||||
"nym-network-defaults",
|
||||
@@ -5673,6 +5709,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-serde-helpers"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bs58 0.5.1",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-service-providers-common"
|
||||
version = "0.1.0"
|
||||
@@ -5692,7 +5737,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.37"
|
||||
version = "1.1.39"
|
||||
dependencies = [
|
||||
"bs58 0.5.1",
|
||||
"clap 4.5.7",
|
||||
@@ -6117,12 +6162,14 @@ dependencies = [
|
||||
"nym-compact-ecash",
|
||||
"nym-config",
|
||||
"nym-credentials",
|
||||
"nym-credentials-interface",
|
||||
"nym-crypto",
|
||||
"nym-ecash-time",
|
||||
"nym-network-defaults",
|
||||
"nym-task",
|
||||
"nym-validator-client",
|
||||
"nyxd-scraper",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_with",
|
||||
"sha2 0.10.8",
|
||||
@@ -6173,12 +6220,14 @@ name = "nym-wireguard"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bincode",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"defguard_wireguard_rs",
|
||||
"ip_network",
|
||||
"log",
|
||||
"nym-crypto",
|
||||
"nym-gateway-storage",
|
||||
"nym-network-defaults",
|
||||
"nym-task",
|
||||
"nym-wireguard-types",
|
||||
@@ -6193,7 +6242,6 @@ name = "nym-wireguard-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"dashmap",
|
||||
"hmac",
|
||||
"log",
|
||||
"nym-config",
|
||||
@@ -6210,7 +6258,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -7914,15 +7962,6 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-helpers"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bs58 0.5.1",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-json-wasm"
|
||||
version = "0.5.0"
|
||||
@@ -8179,7 +8218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
@@ -9026,22 +9065,21 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
version = "1.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"mio 1.0.1",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9056,9 +9094,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10038,6 +10076,7 @@ dependencies = [
|
||||
name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
"getrandom",
|
||||
"gloo-net",
|
||||
|
||||
+9
-8
@@ -52,6 +52,8 @@ members = [
|
||||
"common/ecash-time",
|
||||
"common/execute",
|
||||
"common/exit-policy",
|
||||
"common/gateway-requests",
|
||||
"common/gateway-storage",
|
||||
"common/http-api-client",
|
||||
"common/http-api-common",
|
||||
"common/inclusion-probability",
|
||||
@@ -96,7 +98,6 @@ members = [
|
||||
"explorer-api/explorer-api-requests",
|
||||
"explorer-api/explorer-client",
|
||||
"gateway",
|
||||
"gateway/gateway-requests",
|
||||
"integrations/bity",
|
||||
"mixnode",
|
||||
"sdk/lib/socks5-listener",
|
||||
@@ -139,7 +140,7 @@ default-members = [
|
||||
"tools/nymvisor",
|
||||
"explorer-api",
|
||||
"nym-validator-rewarder",
|
||||
"nym-node"
|
||||
"nym-node",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
@@ -290,11 +291,11 @@ tar = "0.4.40"
|
||||
tempfile = "3.5.0"
|
||||
thiserror = "1.0.48"
|
||||
time = "0.3.30"
|
||||
tokio = "1.33.0"
|
||||
tokio-stream = "0.1.14"
|
||||
tokio-test = "0.4.2"
|
||||
tokio = "1.39"
|
||||
tokio-stream = "0.1.15"
|
||||
tokio-test = "0.4.4"
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = "0.7.10"
|
||||
tokio-util = "0.7.11"
|
||||
toml = "0.8.14"
|
||||
tower = "0.4.13"
|
||||
tower-http = "0.5.2"
|
||||
@@ -346,8 +347,8 @@ bip32 = { version = "0.5.1", default-features = false }
|
||||
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
|
||||
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
|
||||
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
|
||||
tendermint = "0.37.0" # same version as used by cosmrs
|
||||
tendermint-rpc = "0.37.0" # same version as used by cosmrs
|
||||
tendermint = "0.37.0" # same version as used by cosmrs
|
||||
tendermint-rpc = "0.37.0" # same version as used by cosmrs
|
||||
prost = { version = "0.12", default-features = false }
|
||||
|
||||
# wasm-related dependencies
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.37"
|
||||
version = "1.1.39"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -26,30 +26,46 @@ clap = { workspace = true, features = ["cargo", "derive"] }
|
||||
dirs = { workspace = true }
|
||||
log = { workspace = true } # self explanatory
|
||||
rand = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde = { workspace = true, features = [
|
||||
"derive",
|
||||
] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
|
||||
tokio = { workspace = true, features = [
|
||||
"rt-multi-thread",
|
||||
"net",
|
||||
"signal",
|
||||
] } # async runtime
|
||||
tokio-tungstenite = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
## internal
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "clap"] }
|
||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"output_format",
|
||||
"clap",
|
||||
] }
|
||||
nym-client-core = { path = "../../common/client-core", features = [
|
||||
"fs-credentials-storage",
|
||||
"fs-surb-storage",
|
||||
"fs-gateways-storage",
|
||||
"cli",
|
||||
] }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../common/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||
"http-client",
|
||||
] }
|
||||
nym-client-websocket-requests = { path = "websocket-requests" }
|
||||
nym-id = { path = "../../common/nym-id" }
|
||||
|
||||
|
||||
@@ -422,7 +422,7 @@ impl Handler {
|
||||
) {
|
||||
// We don't want a crash in the connection handler to trigger a shutdown of the whole
|
||||
// process.
|
||||
task_client.mark_as_success();
|
||||
task_client.disarm();
|
||||
|
||||
let ws_stream = match accept_async(socket).await {
|
||||
Ok(ws_stream) => ws_stream,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.37"
|
||||
version = "1.1.39"
|
||||
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"
|
||||
@@ -11,7 +11,9 @@ license.workspace = true
|
||||
bs58 = { workspace = true }
|
||||
clap = { workspace = true, features = ["cargo", "derive"] }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde = { workspace = true, features = [
|
||||
"derive",
|
||||
] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
@@ -22,13 +24,21 @@ url = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"output_format",
|
||||
"clap",
|
||||
] }
|
||||
nym-client-core = { path = "../../common/client-core", features = [
|
||||
"fs-credentials-storage",
|
||||
"fs-surb-storage",
|
||||
"fs-gateways-storage",
|
||||
"cli",
|
||||
] }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../common/gateway-requests" }
|
||||
nym-id = { path = "../../common/nym-id" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
@@ -36,7 +46,9 @@ nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||
"http-client",
|
||||
] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -8,6 +8,7 @@ use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
|
||||
use nym_credentials::ecash::utils::obtain_aggregate_wallet;
|
||||
use nym_credentials::IssuedTicketBook;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_ecash_time::{ecash_default_expiration_date, Date};
|
||||
use nym_validator_client::coconut::all_ecash_api_clients;
|
||||
@@ -22,6 +23,7 @@ pub async fn make_deposit<C>(
|
||||
client: &C,
|
||||
client_id: &[u8],
|
||||
expiration: Option<Date>,
|
||||
ticketbook_type: TicketType,
|
||||
) -> Result<IssuanceTicketBook, BandwidthControllerError>
|
||||
where
|
||||
C: EcashSigningClient + EcashQueryClient + Sync,
|
||||
@@ -48,6 +50,7 @@ where
|
||||
deposit_id,
|
||||
client_id,
|
||||
signing_key,
|
||||
ticketbook_type,
|
||||
expiration,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ 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" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../gateway-requests" }
|
||||
nym-metrics = { path = "../nym-metrics" }
|
||||
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
@@ -46,9 +46,12 @@ nym-pemstore = { path = "../pemstore" }
|
||||
nym-topology = { path = "../topology", features = ["serializable"] }
|
||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||
nym-task = { path = "../task" }
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
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-config-types = { path = "./config-types", features = [
|
||||
"disk-persistence",
|
||||
] }
|
||||
nym-client-core-surb-storage = { path = "./surb-storage" }
|
||||
nym-client-core-gateways-storage = { path = "./gateways-storage" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
@@ -115,6 +118,7 @@ tempfile = { workspace = true }
|
||||
[features]
|
||||
default = []
|
||||
cli = ["clap", "comfy-table"]
|
||||
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
|
||||
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
|
||||
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
|
||||
wasm = ["nym-gateway-client/wasm"]
|
||||
|
||||
@@ -18,7 +18,7 @@ url.workspace = true
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
|
||||
nym-crypto = { path = "../../crypto", features = ["asymmetric"] }
|
||||
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||
workspace = true
|
||||
@@ -27,7 +27,12 @@ optional = true
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
|
||||
[features]
|
||||
fs-gateways-storage = ["sqlx"]
|
||||
fs-gateways-storage = ["sqlx"]
|
||||
|
||||
@@ -5,14 +5,15 @@ use crate::cli_helpers::{CliClient, CliClientConfig};
|
||||
use crate::error::ClientCoreError;
|
||||
use nym_credential_storage::models::BasicTicketbookInformation;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_ecash_time::ecash_today;
|
||||
use nym_network_defaults::TicketbookType::MixnetEntry;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::Date;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AvailableTicketbook {
|
||||
pub id: i64,
|
||||
pub typ: TicketType,
|
||||
pub expiration: Date,
|
||||
pub issued_tickets: u32,
|
||||
pub claimed_tickets: u32,
|
||||
@@ -45,6 +46,7 @@ impl AvailableTicketbook {
|
||||
|
||||
vec![
|
||||
comfy_table::Cell::new(self.id.to_string()),
|
||||
comfy_table::Cell::new(self.typ),
|
||||
expiration,
|
||||
comfy_table::Cell::new(format!("{issued} ({si_issued})")),
|
||||
comfy_table::Cell::new(format!("{claimed} ({si_claimed})")),
|
||||
@@ -55,17 +57,22 @@ impl AvailableTicketbook {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasicTicketbookInformation> for AvailableTicketbook {
|
||||
fn from(value: BasicTicketbookInformation) -> Self {
|
||||
AvailableTicketbook {
|
||||
impl TryFrom<BasicTicketbookInformation> for AvailableTicketbook {
|
||||
type Error = ClientCoreError;
|
||||
|
||||
fn try_from(value: BasicTicketbookInformation) -> Result<Self, Self::Error> {
|
||||
let typ = value
|
||||
.ticketbook_type
|
||||
.parse()
|
||||
.map_err(|_| ClientCoreError::UnknownTicketType)?;
|
||||
Ok(AvailableTicketbook {
|
||||
id: value.id,
|
||||
typ,
|
||||
expiration: value.expiration_date,
|
||||
issued_tickets: value.total_tickets,
|
||||
claimed_tickets: value.used_tickets,
|
||||
|
||||
// TODO: this will change when 'type' field is introduced; for now doesn't matter what we put there
|
||||
ticket_size: MixnetEntry.bandwidth_value(),
|
||||
}
|
||||
ticket_size: typ.to_repr().bandwidth_value(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +86,7 @@ impl std::fmt::Display for AvailableTicketbooks {
|
||||
let mut table = comfy_table::Table::new();
|
||||
table.set_header(vec![
|
||||
"id",
|
||||
"type",
|
||||
"expiration",
|
||||
"issued tickets (bandwidth)",
|
||||
"claimed tickets (bandwidth)",
|
||||
@@ -124,6 +132,9 @@ where
|
||||
})?;
|
||||
|
||||
Ok(AvailableTicketbooks(
|
||||
ticketbooks.into_iter().map(Into::into).collect(),
|
||||
ticketbooks
|
||||
.into_iter()
|
||||
.map(TryInto::<AvailableTicketbook>::try_into)
|
||||
.collect::<Result<_, _>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ where
|
||||
Err(ClientCoreError::CustomGatewaySelectionExpected)
|
||||
} else {
|
||||
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
|
||||
shutdown.mark_as_success();
|
||||
shutdown.disarm();
|
||||
custom_gateway_transceiver.set_packet_router(packet_router)?;
|
||||
Ok(custom_gateway_transceiver)
|
||||
};
|
||||
@@ -562,7 +562,7 @@ where
|
||||
if topology_config.disable_refreshing {
|
||||
// if we're not spawning the refresher, don't cause shutdown immediately
|
||||
info!("The topology refesher is not going to be started");
|
||||
shutdown.mark_as_success();
|
||||
shutdown.disarm();
|
||||
} else {
|
||||
// don't spawn the refresher if we don't want to be refreshing the topology.
|
||||
// only use the initial values obtained
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
config::{self, disk_persistence::CommonClientPaths},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-credentials-storage"))]
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
|
||||
|
||||
pub use nym_client_core_gateways_storage as gateways_storage;
|
||||
|
||||
@@ -474,13 +474,6 @@ where
|
||||
Poll::Ready(Some((real_messages, conn_id))) => {
|
||||
log::trace!("handling real_messages: size: {}", real_messages.len());
|
||||
|
||||
// This is the last step in the pipeline where we know the type of the message, so
|
||||
// lets count the number of retransmissions here.
|
||||
if conn_id == TransmissionLane::Retransmission {
|
||||
self.stats_tx
|
||||
.report(PacketStatisticsEvent::RetransmissionQueued);
|
||||
}
|
||||
|
||||
// First store what we got for the given connection id
|
||||
self.transmission_buffer.store(&conn_id, real_messages);
|
||||
let real_next = self.pop_next_message().expect("we just added one");
|
||||
|
||||
@@ -68,6 +68,9 @@ pub enum ClientCoreError {
|
||||
source: Box<dyn Error + Send + Sync>,
|
||||
},
|
||||
|
||||
#[error("the provided ticket type is invalid")]
|
||||
UnknownTicketType,
|
||||
|
||||
#[error("the gateway id is invalid - {0}")]
|
||||
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
|
||||
|
||||
|
||||
@@ -46,13 +46,34 @@ const MEASUREMENTS: usize = 3;
|
||||
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
||||
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
|
||||
struct GatewayWithLatency<'a> {
|
||||
gateway: &'a gateway::Node,
|
||||
// The abstraction that some of these helpers use
|
||||
pub trait ConnectableGateway {
|
||||
fn identity(&self) -> &identity::PublicKey;
|
||||
fn clients_address(&self) -> String;
|
||||
fn is_wss(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ConnectableGateway for gateway::Node {
|
||||
fn identity(&self) -> &identity::PublicKey {
|
||||
self.identity()
|
||||
}
|
||||
|
||||
fn clients_address(&self) -> String {
|
||||
self.clients_address()
|
||||
}
|
||||
|
||||
fn is_wss(&self) -> bool {
|
||||
self.clients_wss_port.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
struct GatewayWithLatency<'a, G: ConnectableGateway> {
|
||||
gateway: &'a G,
|
||||
latency: Duration,
|
||||
}
|
||||
|
||||
impl<'a> GatewayWithLatency<'a> {
|
||||
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
|
||||
impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
|
||||
fn new(gateway: &'a G, latency: Duration) -> Self {
|
||||
GatewayWithLatency { gateway, latency }
|
||||
}
|
||||
}
|
||||
@@ -130,11 +151,14 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
|
||||
}
|
||||
|
||||
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
|
||||
async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, ClientCoreError>
|
||||
where
|
||||
G: ConnectableGateway,
|
||||
{
|
||||
let addr = gateway.clients_address();
|
||||
trace!(
|
||||
"establishing connection to {} ({addr})...",
|
||||
gateway.identity_key,
|
||||
gateway.identity(),
|
||||
);
|
||||
let mut stream = connect(&addr).await?;
|
||||
|
||||
@@ -177,7 +201,7 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
let count = results.len() as u64;
|
||||
if count == 0 {
|
||||
return Err(ClientCoreError::NoGatewayMeasurements {
|
||||
identity: gateway.identity_key.to_base58_string(),
|
||||
identity: gateway.identity().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,11 +211,11 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
Ok(GatewayWithLatency::new(gateway, avg))
|
||||
}
|
||||
|
||||
pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
) -> Result<G, ClientCoreError> {
|
||||
let gateways = filter_by_tls(gateways, must_use_tls)?;
|
||||
|
||||
info!(
|
||||
@@ -223,21 +247,19 @@ pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
|
||||
info!(
|
||||
"chose gateway {} with average latency of {:?}",
|
||||
chosen.gateway.identity_key, chosen.latency
|
||||
chosen.gateway.identity(),
|
||||
chosen.latency
|
||||
);
|
||||
|
||||
Ok(chosen.gateway.clone())
|
||||
}
|
||||
|
||||
fn filter_by_tls(
|
||||
gateways: &[gateway::Node],
|
||||
fn filter_by_tls<G: ConnectableGateway>(
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
|
||||
) -> Result<Vec<&G>, ClientCoreError> {
|
||||
if must_use_tls {
|
||||
let filtered = gateways
|
||||
.iter()
|
||||
.filter(|g| g.clients_wss_port.is_some())
|
||||
.collect::<Vec<_>>();
|
||||
let filtered = gateways.iter().filter(|g| g.is_wss()).collect::<Vec<_>>();
|
||||
|
||||
if filtered.is_empty() {
|
||||
return Err(ClientCoreError::NoWssGateways);
|
||||
|
||||
@@ -2,7 +2,9 @@ use std::future::Future;
|
||||
|
||||
#[cfg(all(
|
||||
not(target_arch = "wasm32"),
|
||||
feature = "cli",
|
||||
feature = "fs-surb-storage",
|
||||
feature = "fs-credentials-storage",
|
||||
feature = "fs-gateways-storage"
|
||||
))]
|
||||
pub mod cli_helpers;
|
||||
|
||||
@@ -24,7 +24,7 @@ nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
||||
nym-credentials = { path = "../../credentials" }
|
||||
nym-credential-storage = { path = "../../credential-storage" }
|
||||
nym-crypto = { path = "../../crypto" }
|
||||
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
nym-pemstore = { path = "../../pemstore" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::GatewayClientError;
|
||||
use nym_network_defaults::TicketbookType::MixnetEntry;
|
||||
use nym_network_defaults::TicketTypeRepr::V1MixnetEntry;
|
||||
use si_scale::helpers::bibytes2;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -103,7 +103,7 @@ impl BandwidthTickets {
|
||||
|
||||
// 20% of entry ticket value
|
||||
pub const DEFAULT_REMAINING_BANDWIDTH_THRESHOLD: i64 =
|
||||
(MixnetEntry.bandwidth_value() / 5) as i64;
|
||||
(V1MixnetEntry.bandwidth_value() / 5) as i64;
|
||||
|
||||
pub const DEFAULT_CUTOFF_REMAINING_BANDWIDTH_THRESHOLD: Option<i64> = None;
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ impl PacketRouter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mark_as_success(&mut self) {
|
||||
self.shutdown.mark_as_success();
|
||||
pub fn disarm(&mut self) {
|
||||
self.shutdown.disarm();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,8 +113,8 @@ impl PartiallyDelegatedRouter {
|
||||
let return_res = match ret {
|
||||
Err(err) => self.stream_return.send(Err(err)),
|
||||
Ok(_) => {
|
||||
self.packet_router.mark_as_success();
|
||||
task_client.mark_as_success();
|
||||
self.packet_router.disarm();
|
||||
task_client.disarm();
|
||||
self.stream_return.send(Ok(split_stream))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,8 +23,8 @@ use nym_api_requests::ecash::VerificationKeyResponse;
|
||||
pub use nym_api_requests::{
|
||||
ecash::{
|
||||
models::{
|
||||
EpochCredentialsResponse, IssuedCredential, IssuedCredentialBody,
|
||||
IssuedCredentialResponse, IssuedCredentialsResponse, SpentCredentialsResponse,
|
||||
EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse,
|
||||
IssuedTicketbook, IssuedTicketbookBody, SpentCredentialsResponse,
|
||||
},
|
||||
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody,
|
||||
PartialCoinIndicesSignatureResponse, PartialExpirationDateSignatureResponse,
|
||||
|
||||
@@ -683,6 +683,24 @@ pub trait MixnetSigningClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn migrate_vested_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateVestedMixNode {}, vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn migrate_vested_delegation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::MigrateVestedDelegation { mix_id },
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "contract-testing")]
|
||||
async fn testing_resolve_all_pending_events(
|
||||
&self,
|
||||
@@ -928,6 +946,12 @@ mod tests {
|
||||
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
|
||||
.withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None)
|
||||
.ignore(),
|
||||
MixnetExecuteMsg::MigrateVestedMixNode { .. } => {
|
||||
client.migrate_vested_mixnode(None).ignore()
|
||||
}
|
||||
MixnetExecuteMsg::MigrateVestedDelegation { mix_id } => {
|
||||
client.migrate_vested_delegation(mix_id, None).ignore()
|
||||
}
|
||||
|
||||
#[cfg(feature = "contract-testing")]
|
||||
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
|
||||
|
||||
@@ -437,6 +437,7 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
|
||||
use nym_vesting_contract_common::ExecuteMsg;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
@@ -560,6 +561,9 @@ mod tests {
|
||||
VestingExecuteMsg::UpdateLockedPledgeCap { address, cap } => client
|
||||
.update_locked_pledge_cap(address.parse().unwrap(), cap, None)
|
||||
.ignore(),
|
||||
// those will never be manually called by clients
|
||||
ExecuteMsg::TrackMigratedMixnode { .. } => "explicitly_ignored".ignore(),
|
||||
ExecuteMsg::TrackMigratedDelegation { .. } => "explicitly_ignored".ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TEMPORARY WORKAROUND:
|
||||
// those features are expected as the below should only get activated whenever
|
||||
// the corresponding features in tendermint-rpc are enabled transitively
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
use crate::nyxd::cosmwasm_client::client_traits::SigningCosmWasmClient;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Config, GasPrice, Hash, Height};
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TEMPORARY WORKAROUND:
|
||||
// those features are expected as the below should only get activated whenever
|
||||
// the corresponding features in tendermint-rpc are enabled transitively
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
use crate::nyxd::contract_traits::{NymContractsProvider, TypedNymContracts};
|
||||
use crate::nyxd::cosmwasm_client::types::{
|
||||
ChangeAdminResult, ContractCodeId, ExecuteResult, InstantiateOptions, InstantiateResult,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TEMPORARY WORKAROUND:
|
||||
// those features are expected as the below should only get activated whenever
|
||||
// the corresponding features in tendermint-rpc are enabled transitively
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::tendermint::{self, abci, block::Height, evidence::Evidence, Genesis, Hash};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
@@ -7,11 +7,16 @@ use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use nym_credential_storage::initialise_persistent_storage;
|
||||
use nym_credential_utils::utils;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Specify which type of ticketbook should be issued
|
||||
#[clap(long, default_value_t = TicketType::default())]
|
||||
pub(crate) ticketbook_type: TicketType,
|
||||
|
||||
/// Config file of the client that is supposed to use the credential.
|
||||
#[clap(long)]
|
||||
pub(crate) client_config: PathBuf,
|
||||
@@ -39,7 +44,13 @@ pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
|
||||
let persistent_storage = initialise_persistent_storage(credentials_store).await;
|
||||
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
|
||||
utils::issue_credential(&client, &persistent_storage, &private_id_key.to_bytes()).await?;
|
||||
utils::issue_credential(
|
||||
&client,
|
||||
&persistent_storage,
|
||||
&private_id_key.to_bytes(),
|
||||
args.ticketbook_type,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use log::{debug, info};
|
||||
|
||||
use cosmwasm_std::Decimal;
|
||||
use nym_mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent};
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use log::{debug, info};
|
||||
use nym_mixnet_contract_common::{
|
||||
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
|
||||
};
|
||||
use nym_network_defaults::mainnet::MIX_DENOM;
|
||||
use nym_network_defaults::TOTAL_SUPPLY;
|
||||
use nym_validator_client::nyxd::{AccountId, Coin};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn default_maximum_operating_cost() -> Coin {
|
||||
Coin::new(TOTAL_SUPPLY, MIX_DENOM.base)
|
||||
}
|
||||
|
||||
pub fn default_minimum_operating_cost() -> Coin {
|
||||
Coin::new(0, MIX_DENOM.base)
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
@@ -50,6 +61,18 @@ pub struct Args {
|
||||
|
||||
#[clap(long, default_value_t = 240)]
|
||||
pub active_set_size: u32,
|
||||
|
||||
#[clap(long, default_value_t = Percent::zero())]
|
||||
pub minimum_profit_margin_percent: Percent,
|
||||
|
||||
#[clap(long, default_value_t = Percent::hundred())]
|
||||
pub maximum_profit_margin_percent: Percent,
|
||||
|
||||
#[clap(long, default_value_t = default_minimum_operating_cost())]
|
||||
pub minimum_interval_operating_cost: Coin,
|
||||
|
||||
#[clap(long, default_value_t = default_maximum_operating_cost())]
|
||||
pub maximum_interval_operating_cost: Coin,
|
||||
}
|
||||
|
||||
pub async fn generate(args: Args) {
|
||||
@@ -97,6 +120,10 @@ pub async fn generate(args: Args) {
|
||||
.expect("Rewarding (mix) denom has to be set")
|
||||
});
|
||||
|
||||
if args.minimum_interval_operating_cost.denom != args.maximum_interval_operating_cost.denom {
|
||||
panic!("different denoms for operating cost bounds")
|
||||
}
|
||||
|
||||
let instantiate_msg = InstantiateMsg {
|
||||
rewarding_validator_address: rewarding_validator_address.to_string(),
|
||||
vesting_contract_address: vesting_contract_address.to_string(),
|
||||
@@ -104,6 +131,14 @@ pub async fn generate(args: Args) {
|
||||
epochs_in_interval: args.epochs_in_interval,
|
||||
epoch_duration: Duration::from_secs(args.epoch_duration),
|
||||
initial_rewarding_params,
|
||||
profit_margin: ProfitMarginRange {
|
||||
minimum: args.minimum_profit_margin_percent,
|
||||
maximum: args.maximum_profit_margin_percent,
|
||||
},
|
||||
interval_operating_cost: OperatingCostRange {
|
||||
minimum: args.minimum_interval_operating_cost.amount.into(),
|
||||
maximum: args.maximum_interval_operating_cost.amount.into(),
|
||||
},
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::MixId;
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
pub mix_id: Option<MixId>,
|
||||
|
||||
#[clap(long)]
|
||||
pub identity_key: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn migrate_vested_delegation(args: Args, client: SigningClient) {
|
||||
let mix_id = match args.mix_id {
|
||||
Some(mix_id) => mix_id,
|
||||
None => {
|
||||
let identity_key = args
|
||||
.identity_key
|
||||
.expect("either mix_id or mix_identity has to be specified");
|
||||
let node_details = client
|
||||
.get_mixnode_details_by_identity(identity_key)
|
||||
.await
|
||||
.expect("contract query failed")
|
||||
.mixnode_details
|
||||
.expect("mixnode with the specified identity doesnt exist");
|
||||
node_details.mix_id()
|
||||
}
|
||||
};
|
||||
|
||||
let res = client
|
||||
.migrate_vested_delegation(mix_id, None)
|
||||
.await
|
||||
.expect("failed to migrate delegation!");
|
||||
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ pub mod rewards;
|
||||
|
||||
pub mod delegate_to_mixnode;
|
||||
pub mod delegate_to_multiple_mixnodes;
|
||||
pub mod migrate_vested_delegation;
|
||||
pub mod query_for_delegations;
|
||||
pub mod undelegate_from_mixnode;
|
||||
pub mod vesting_delegate_to_mixnode;
|
||||
@@ -35,4 +36,6 @@ pub enum MixnetDelegatorsCommands {
|
||||
DelegateVesting(vesting_delegate_to_mixnode::Args),
|
||||
/// Undelegate from a mixnode (when originally using locked tokens)
|
||||
UndelegateVesting(vesting_undelegate_from_mixnode::Args),
|
||||
/// Migrate the delegation to use liquid tokens
|
||||
MigrateVestedDelegation(migrate_vested_delegation::Args),
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
|
||||
mix_id,
|
||||
amount,
|
||||
proxy,
|
||||
..
|
||||
} => {
|
||||
if owner.as_str() == client.nyxd.address().as_ref() {
|
||||
table.add_row(vec![
|
||||
@@ -111,6 +112,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
|
||||
owner,
|
||||
mix_id,
|
||||
proxy,
|
||||
..
|
||||
} => {
|
||||
if owner.as_str() == client.nyxd.address().as_ref() {
|
||||
table.add_row(vec![
|
||||
|
||||
+2
-13
@@ -8,7 +8,7 @@ use cosmwasm_std::Coin;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_mixnet_contract_common::construct_gateway_bonding_sign_payload;
|
||||
use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT};
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
@@ -39,10 +39,6 @@ pub struct Args {
|
||||
)]
|
||||
pub amount: u128,
|
||||
|
||||
/// Indicates whether the gateway is going to get bonded via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
@@ -74,15 +70,8 @@ pub async fn create_payload(args: Args, client: SigningClient) {
|
||||
};
|
||||
|
||||
let address = account_id_to_cw_addr(&client.address());
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(
|
||||
client.vesting_contract_address().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let payload = construct_gateway_bonding_sign_payload(nonce, address, proxy, coin, gateway);
|
||||
let payload = construct_gateway_bonding_sign_payload(nonce, address, coin, gateway);
|
||||
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
|
||||
println!("{}", args.output.format(&wrapper))
|
||||
}
|
||||
|
||||
@@ -5,33 +5,21 @@ use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Label that is going to be used for creating the family
|
||||
#[arg(long)]
|
||||
pub family_label: String,
|
||||
|
||||
/// Indicates whether the family is going to get created via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn create_family(args: Args, client: SigningClient) {
|
||||
info!("Create family");
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family")
|
||||
};
|
||||
let res = client
|
||||
.create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family");
|
||||
|
||||
info!("Family creation result: {:?}", res);
|
||||
}
|
||||
|
||||
+3
-16
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::QueryClient;
|
||||
use crate::utils::{account_id_to_cw_addr, DataWrapper};
|
||||
use crate::utils::DataWrapper;
|
||||
use clap::Parser;
|
||||
use cosmrs::AccountId;
|
||||
use log::info;
|
||||
@@ -10,7 +10,7 @@ use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::construct_family_join_permit;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
@@ -18,10 +18,6 @@ pub struct Args {
|
||||
#[arg(long)]
|
||||
pub address: AccountId,
|
||||
|
||||
/// Indicates whether the member joining the family is going to use the vesting account for joining.
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
// might as well validate the value when parsing the arguments
|
||||
/// Identity of the member for whom we're issuing the permit
|
||||
#[arg(long)]
|
||||
@@ -68,18 +64,9 @@ pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryCli
|
||||
}
|
||||
};
|
||||
|
||||
// let address = account_id_to_cw_addr(&args.address);
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(
|
||||
client.vesting_contract_address().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let head = FamilyHead::new(mixnode.bond_information.identity());
|
||||
|
||||
let payload = construct_family_join_permit(nonce, head, proxy, args.member.to_base58_string());
|
||||
let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string());
|
||||
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
|
||||
println!("{}", args.output.format(&wrapper))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
@@ -16,10 +15,6 @@ pub struct Args {
|
||||
#[arg(long)]
|
||||
pub family_head: identity::PublicKey,
|
||||
|
||||
/// Indicates whether the member joining the family is going to do so via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
/// Permission, as provided by the family head, for joining the family
|
||||
#[arg(long)]
|
||||
pub join_permit: MessageSignature,
|
||||
@@ -30,17 +25,10 @@ pub async fn join_family(args: Args, client: SigningClient) {
|
||||
|
||||
let family_head = FamilyHead::new(args.family_head.to_base58_string());
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family")
|
||||
};
|
||||
let res = client
|
||||
.join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family");
|
||||
|
||||
info!("Family join result: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -7,17 +7,12 @@ use log::info;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// The head of the family that we intend to leave
|
||||
#[arg(long)]
|
||||
pub family_head: identity::PublicKey,
|
||||
|
||||
/// Indicates whether we joined the family via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn leave_family(args: Args, client: SigningClient) {
|
||||
@@ -25,17 +20,10 @@ pub async fn leave_family(args: Args, client: SigningClient) {
|
||||
|
||||
let family_head = FamilyHead::new(args.family_head.to_base58_string());
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family")
|
||||
};
|
||||
let res = client
|
||||
.leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family");
|
||||
|
||||
info!("Family leave result: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {}
|
||||
|
||||
pub async fn migrate_vested_mixnode(_args: Args, client: SigningClient) {
|
||||
let res = client
|
||||
.migrate_vested_mixnode(None)
|
||||
.await
|
||||
.expect("failed to migrate mixnode!");
|
||||
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
+2
-13
@@ -11,7 +11,7 @@ use nym_mixnet_contract_common::{construct_mixnode_bonding_sign_payload, MixNode
|
||||
use nym_network_defaults::{
|
||||
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
|
||||
};
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
||||
use nym_validator_client::nyxd::CosmWasmCoin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -52,10 +52,6 @@ pub struct Args {
|
||||
)]
|
||||
pub amount: u128,
|
||||
|
||||
/// Indicates whether the mixnode is going to get bonded via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
@@ -100,16 +96,9 @@ pub async fn create_payload(args: Args, client: SigningClient) {
|
||||
};
|
||||
|
||||
let address = account_id_to_cw_addr(&client.address());
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(
|
||||
client.vesting_contract_address().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let payload =
|
||||
construct_mixnode_bonding_sign_payload(nonce, address, proxy, coin, mixnode, cost_params);
|
||||
construct_mixnode_bonding_sign_payload(nonce, address, coin, mixnode, cost_params);
|
||||
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
|
||||
println!("{}", args.output.format(&wrapper))
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ pub mod bond_mixnode;
|
||||
pub mod decrease_pledge;
|
||||
pub mod families;
|
||||
pub mod keys;
|
||||
pub mod migrate_vested_mixnode;
|
||||
pub mod mixnode_bonding_sign_payload;
|
||||
pub mod pledge_more;
|
||||
pub mod rewards;
|
||||
@@ -52,4 +53,6 @@ pub enum MixnetOperatorsMixnodeCommands {
|
||||
DecreasePledge(decrease_pledge::Args),
|
||||
/// Decrease pledge with locked tokens
|
||||
DecreasePledgeVesting(vesting_decrease_pledge::Args),
|
||||
/// Migrate the mixnode to use liquid tokens
|
||||
MigrateVestedNode(migrate_vested_mixnode::Args),
|
||||
}
|
||||
|
||||
@@ -218,7 +218,6 @@ where
|
||||
#[derive(Serialize)]
|
||||
pub struct ContractMessageContent<T> {
|
||||
pub sender: Addr,
|
||||
pub proxy: Option<Addr>,
|
||||
pub funds: Vec<Coin>,
|
||||
pub data: T,
|
||||
}
|
||||
@@ -233,25 +232,17 @@ where
|
||||
}
|
||||
|
||||
impl<T> ContractMessageContent<T> {
|
||||
pub fn new(sender: Addr, proxy: Option<Addr>, funds: Vec<Coin>, data: T) -> Self {
|
||||
pub fn new(sender: Addr, funds: Vec<Coin>, data: T) -> Self {
|
||||
ContractMessageContent {
|
||||
sender,
|
||||
proxy,
|
||||
funds,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_info(info: MessageInfo, signer: Addr, data: T) -> Self {
|
||||
let proxy = if info.sender == signer {
|
||||
None
|
||||
} else {
|
||||
Some(info.sender)
|
||||
};
|
||||
|
||||
ContractMessageContent {
|
||||
sender: signer,
|
||||
proxy,
|
||||
funds: info.funds,
|
||||
data,
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ use cosmwasm_std::Coin;
|
||||
#[cw_serde]
|
||||
pub struct PoolCounters {
|
||||
pub total_deposited: Coin,
|
||||
pub total_redeemed_gateways: Coin,
|
||||
pub total_redeemed_holding: Coin,
|
||||
pub total_redeemed: Coin,
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ impl Delegation {
|
||||
cumulative_reward_ratio: Decimal,
|
||||
amount: Coin,
|
||||
height: u64,
|
||||
proxy: Option<Addr>,
|
||||
) -> Self {
|
||||
assert!(
|
||||
amount.amount <= TOKEN_SUPPLY,
|
||||
@@ -78,7 +77,7 @@ impl Delegation {
|
||||
cumulative_reward_ratio,
|
||||
amount,
|
||||
height,
|
||||
proxy,
|
||||
proxy: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{EpochEventId, EpochState, IdentityKey, MixId};
|
||||
use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, ProfitMarginRange};
|
||||
use contracts_common::signing::verifier::ApiVerifierError;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -76,21 +77,11 @@ pub enum MixnetContractError {
|
||||
#[error("Received multiple coin types during staking")]
|
||||
MultipleDenoms,
|
||||
|
||||
#[error("Proxy address mismatch, expected {existing}, got {incoming}")]
|
||||
ProxyMismatch { existing: String, incoming: String },
|
||||
|
||||
#[error("Proxy address ({received}) is not set to the vesting contract ({vesting_contract})")]
|
||||
ProxyIsNotVestingContract {
|
||||
received: Addr,
|
||||
vesting_contract: Addr,
|
||||
},
|
||||
#[error(
|
||||
"Sender of this message ({received}) is not the vesting contract ({vesting_contract})"
|
||||
)]
|
||||
SenderIsNotVestingContract {
|
||||
received: Addr,
|
||||
vesting_contract: Addr,
|
||||
},
|
||||
|
||||
#[error("Failed to recover ed25519 public key from its base58 representation - {0}")]
|
||||
MalformedEd25519IdentityKey(String),
|
||||
@@ -239,6 +230,30 @@ pub enum MixnetContractError {
|
||||
#[from]
|
||||
source: ApiVerifierError,
|
||||
},
|
||||
|
||||
#[error("this operation is no longer allowed to be performed with vesting tokens. please move them to your liquid balance and try again")]
|
||||
DisabledVestingOperation,
|
||||
|
||||
#[error(
|
||||
"this mixnode has not been bonded with the vesting tokens or has already been migrated"
|
||||
)]
|
||||
NotAVestingMixnode,
|
||||
|
||||
#[error("this delegation has not been performed with the vesting tokens or has already been migrated")]
|
||||
NotAVestingDelegation,
|
||||
|
||||
#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
|
||||
ProfitMarginOutsideRange {
|
||||
provided: Percent,
|
||||
range: ProfitMarginRange,
|
||||
},
|
||||
|
||||
#[error("the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}")]
|
||||
OperatingCostOutsideRange {
|
||||
denom: String,
|
||||
provided: Uint128,
|
||||
range: OperatingCostRange,
|
||||
},
|
||||
}
|
||||
|
||||
impl MixnetContractError {
|
||||
|
||||
@@ -103,7 +103,6 @@ impl Display for MixnetEventType {
|
||||
// attributes that are used in multiple places
|
||||
pub const OWNER_KEY: &str = "owner";
|
||||
pub const AMOUNT_KEY: &str = "amount";
|
||||
pub const PROXY_KEY: &str = "proxy";
|
||||
|
||||
// event-specific attributes
|
||||
|
||||
@@ -163,7 +162,6 @@ pub const NEW_EPOCHS_IN_INTERVAL: &str = "new_epochs_in_interval";
|
||||
pub fn new_delegation_event(
|
||||
created_at: BlockHeight,
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
mix_id: MixId,
|
||||
unit_reward: Decimal,
|
||||
@@ -171,58 +169,34 @@ pub fn new_delegation_event(
|
||||
Event::new(MixnetEventType::Delegation)
|
||||
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
.add_attribute(UNIT_REWARD_KEY, unit_reward.to_string())
|
||||
}
|
||||
|
||||
pub fn new_delegation_on_unbonded_node_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
pub fn new_delegation_on_unbonded_node_event(delegator: &Addr, mix_id: MixId) -> Event {
|
||||
Event::new(MixnetEventType::Delegation)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_pending_delegation_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
pub fn new_pending_delegation_event(delegator: &Addr, amount: &Coin, mix_id: MixId) -> Event {
|
||||
Event::new(MixnetEventType::PendingDelegation)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_withdraw_operator_reward_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: Coin,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
pub fn new_withdraw_operator_reward_event(owner: &Addr, amount: Coin, mix_id: MixId) -> Event {
|
||||
Event::new(MixnetEventType::WithdrawOperatorReward)
|
||||
.add_attribute(OWNER_KEY, owner.as_str())
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_withdraw_delegator_reward_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: Coin,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
pub fn new_withdraw_delegator_reward_event(delegator: &Addr, amount: Coin, mix_id: MixId) -> Event {
|
||||
Event::new(MixnetEventType::WithdrawDelegatorReward)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
}
|
||||
@@ -278,59 +252,43 @@ pub fn new_pending_rewarding_params_update_event(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_undelegation_event(
|
||||
created_at: BlockHeight,
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
pub fn new_undelegation_event(created_at: BlockHeight, delegator: &Addr, mix_id: MixId) -> Event {
|
||||
Event::new(MixnetEventType::Undelegation)
|
||||
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_pending_undelegation_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
pub fn new_pending_undelegation_event(delegator: &Addr, mix_id: MixId) -> Event {
|
||||
Event::new(MixnetEventType::PendingUndelegation)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_gateway_bonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::GatewayBonding)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
|
||||
pub fn new_gateway_unbonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::GatewayUnbonding)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
|
||||
pub fn new_mixnode_bonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
mix_id: MixId,
|
||||
@@ -341,7 +299,6 @@ pub fn new_mixnode_bonding_event(
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(ASSIGNED_LAYER_KEY, assigned_layer)
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
@@ -380,7 +337,6 @@ pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Ev
|
||||
|
||||
pub fn new_pending_mixnode_unbonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
@@ -388,43 +344,33 @@ pub fn new_pending_mixnode_unbonding_event(
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
}
|
||||
|
||||
pub fn new_mixnode_config_update_event(
|
||||
mix_id: MixId,
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
update: &MixNodeConfigUpdate,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::MixnodeConfigUpdate)
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(UPDATED_MIXNODE_CONFIG_KEY, update.to_inline_json())
|
||||
}
|
||||
|
||||
pub fn new_gateway_config_update_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
update: &GatewayConfigUpdate,
|
||||
) -> Event {
|
||||
pub fn new_gateway_config_update_event(owner: &Addr, update: &GatewayConfigUpdate) -> Event {
|
||||
Event::new(MixnetEventType::GatewayConfigUpdate)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(UPDATED_GATEWAY_CONFIG_KEY, update.to_inline_json())
|
||||
}
|
||||
|
||||
pub fn new_mixnode_pending_cost_params_update_event(
|
||||
mix_id: MixId,
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
new_costs: &MixNodeCostParams,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::PendingMixnodeCostParamsUpdate)
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(UPDATED_MIXNODE_COST_PARAMS_KEY, new_costs.to_inline_json())
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crate::{IdentityKey, IdentityKeyRef};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Addr;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@@ -84,10 +83,10 @@ impl FamilyHead {
|
||||
}
|
||||
|
||||
impl Family {
|
||||
pub fn new(head: FamilyHead, proxy: Option<Addr>, label: String) -> Self {
|
||||
pub fn new(head: FamilyHead, label: String) -> Self {
|
||||
Family {
|
||||
head,
|
||||
proxy: proxy.map(|p| p.to_string()),
|
||||
proxy: None,
|
||||
label,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,19 +55,13 @@ pub struct GatewayBond {
|
||||
}
|
||||
|
||||
impl GatewayBond {
|
||||
pub fn new(
|
||||
pledge_amount: Coin,
|
||||
owner: Addr,
|
||||
block_height: u64,
|
||||
gateway: Gateway,
|
||||
proxy: Option<Addr>,
|
||||
) -> Self {
|
||||
pub fn new(pledge_amount: Coin, owner: Addr, block_height: u64, gateway: Gateway) -> Self {
|
||||
GatewayBond {
|
||||
pledge_amount,
|
||||
owner,
|
||||
block_height,
|
||||
gateway,
|
||||
proxy,
|
||||
proxy: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@ use crate::helpers::IntoBaseDecimal;
|
||||
use crate::reward_params::{NodeRewardParams, RewardingParams};
|
||||
use crate::rewarding::helpers::truncate_reward;
|
||||
use crate::rewarding::RewardDistribution;
|
||||
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
|
||||
use crate::{
|
||||
Delegation, EpochEventId, EpochId, IdentityKey, MixId, OperatingCostRange, Percent,
|
||||
ProfitMarginRange, SphinxKey,
|
||||
};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
|
||||
use schemars::JsonSchema;
|
||||
@@ -152,6 +155,16 @@ impl MixNodeRewarding {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalise_profit_margin(&mut self, allowed_range: ProfitMarginRange) {
|
||||
self.cost_params.profit_margin_percent =
|
||||
allowed_range.normalise(self.cost_params.profit_margin_percent)
|
||||
}
|
||||
|
||||
pub fn normalise_operating_cost(&mut self, allowed_range: OperatingCostRange) {
|
||||
self.cost_params.interval_operating_cost.amount =
|
||||
allowed_range.normalise(self.cost_params.interval_operating_cost.amount)
|
||||
}
|
||||
|
||||
/// Determines whether this node is still bonded. This is performed via a simple check,
|
||||
/// if there are no tokens left associated with the operator, it means they have unbonded
|
||||
/// and those params only exist for the purposes of calculating rewards for delegators that
|
||||
@@ -518,7 +531,6 @@ impl MixNodeBond {
|
||||
original_pledge: Coin,
|
||||
layer: Layer,
|
||||
mix_node: MixNode,
|
||||
proxy: Option<Addr>,
|
||||
bonding_height: u64,
|
||||
) -> Self {
|
||||
MixNodeBond {
|
||||
@@ -527,7 +539,7 @@ impl MixNodeBond {
|
||||
original_pledge,
|
||||
layer,
|
||||
mix_node,
|
||||
proxy,
|
||||
proxy: None,
|
||||
bonding_height,
|
||||
is_unbonding: false,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::delegation::{self, OwnerProxySubKey};
|
||||
@@ -12,6 +12,7 @@ use crate::reward_params::{
|
||||
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
|
||||
};
|
||||
use crate::types::{ContractStateParams, LayerAssignment, MixId};
|
||||
use crate::{OperatingCostRange, ProfitMarginRange};
|
||||
use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Coin, Decimal};
|
||||
@@ -57,6 +58,12 @@ pub struct InstantiateMsg {
|
||||
pub epochs_in_interval: u32,
|
||||
pub epoch_duration: Duration,
|
||||
pub initial_rewarding_params: InitialRewardingParams,
|
||||
|
||||
#[serde(default)]
|
||||
pub profit_margin: ProfitMarginRange,
|
||||
|
||||
#[serde(default)]
|
||||
pub interval_operating_cost: OperatingCostRange,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
@@ -269,6 +276,12 @@ pub enum ExecuteMsg {
|
||||
owner: String,
|
||||
},
|
||||
|
||||
// vesting migration:
|
||||
MigrateVestedMixNode {},
|
||||
MigrateVestedDelegation {
|
||||
mix_id: MixId,
|
||||
},
|
||||
|
||||
// testing-only
|
||||
#[cfg(feature = "contract-testing")]
|
||||
TestingResolveAllPendingEvents {
|
||||
@@ -381,6 +394,9 @@ impl ExecuteMsg {
|
||||
ExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, .. } => {
|
||||
format!("withdrawing delegator reward from mixnode {mix_id} on behalf")
|
||||
}
|
||||
ExecuteMsg::MigrateVestedMixNode { .. } => "migrate vested mixnode".into(),
|
||||
ExecuteMsg::MigrateVestedDelegation { .. } => "migrate vested delegation".to_string(),
|
||||
|
||||
#[cfg(feature = "contract-testing")]
|
||||
ExecuteMsg::TestingResolveAllPendingEvents { .. } => {
|
||||
"resolving all pending events".into()
|
||||
|
||||
@@ -38,6 +38,7 @@ pub enum PendingEpochEventKind {
|
||||
/// Request to create a delegation towards particular mixnode.
|
||||
/// Note that if such delegation already exists, it will get updated with the provided token amount.
|
||||
#[serde(alias = "Delegate")]
|
||||
#[non_exhaustive]
|
||||
Delegate {
|
||||
/// The address of the owner of the delegation.
|
||||
owner: Addr,
|
||||
@@ -55,6 +56,7 @@ pub enum PendingEpochEventKind {
|
||||
|
||||
/// Request to remove delegation from particular mixnode.
|
||||
#[serde(alias = "Undelegate")]
|
||||
#[non_exhaustive]
|
||||
Undelegate {
|
||||
/// The address of the owner of the delegation.
|
||||
owner: Addr,
|
||||
@@ -109,6 +111,23 @@ impl PendingEpochEventKind {
|
||||
kind: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_delegate(owner: Addr, mix_id: MixId, amount: Coin) -> Self {
|
||||
PendingEpochEventKind::Delegate {
|
||||
owner,
|
||||
mix_id,
|
||||
amount,
|
||||
proxy: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_undelegate(owner: Addr, mix_id: MixId) -> Self {
|
||||
PendingEpochEventKind::Undelegate {
|
||||
owner,
|
||||
mix_id,
|
||||
proxy: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(EpochEventId, PendingEpochEventData)> for PendingEpochEvent {
|
||||
|
||||
-1
@@ -47,7 +47,6 @@ impl SimulatedNode {
|
||||
self.rewarding_details.total_unit_reward,
|
||||
delegation,
|
||||
42,
|
||||
None,
|
||||
);
|
||||
|
||||
self.delegations.insert(delegator, delegation);
|
||||
|
||||
@@ -37,13 +37,12 @@ impl SigningPurpose for MixnodeBondingPayload {
|
||||
pub fn construct_mixnode_bonding_sign_payload(
|
||||
nonce: Nonce,
|
||||
sender: Addr,
|
||||
proxy: Option<Addr>,
|
||||
pledge: Coin,
|
||||
mix_node: MixNode,
|
||||
cost_params: MixNodeCostParams,
|
||||
) -> SignableMixNodeBondingMsg {
|
||||
let payload = MixnodeBondingPayload::new(mix_node, cost_params);
|
||||
let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);
|
||||
let content = ContractMessageContent::new(sender, vec![pledge], payload);
|
||||
|
||||
SignableMessage::new(nonce, content)
|
||||
}
|
||||
@@ -68,12 +67,11 @@ impl SigningPurpose for GatewayBondingPayload {
|
||||
pub fn construct_gateway_bonding_sign_payload(
|
||||
nonce: Nonce,
|
||||
sender: Addr,
|
||||
proxy: Option<Addr>,
|
||||
pledge: Coin,
|
||||
gateway: Gateway,
|
||||
) -> SignableGatewayBondingMsg {
|
||||
let payload = GatewayBondingPayload::new(gateway);
|
||||
let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);
|
||||
let content = ContractMessageContent::new(sender, vec![pledge], payload);
|
||||
|
||||
SignableMessage::new(nonce, content)
|
||||
}
|
||||
@@ -82,17 +80,14 @@ pub fn construct_gateway_bonding_sign_payload(
|
||||
pub struct FamilyJoinPermit {
|
||||
// the granter of this permit
|
||||
family_head: FamilyHead,
|
||||
// whether the **member** will want to join via the proxy (i.e. vesting contract)
|
||||
proxy: Option<Addr>,
|
||||
// the actual member we want to permit to join
|
||||
member_node: IdentityKey,
|
||||
}
|
||||
|
||||
impl FamilyJoinPermit {
|
||||
pub fn new(family_head: FamilyHead, proxy: Option<Addr>, member_node: IdentityKey) -> Self {
|
||||
pub fn new(family_head: FamilyHead, member_node: IdentityKey) -> Self {
|
||||
Self {
|
||||
family_head,
|
||||
proxy,
|
||||
member_node,
|
||||
}
|
||||
}
|
||||
@@ -107,10 +102,9 @@ impl SigningPurpose for FamilyJoinPermit {
|
||||
pub fn construct_family_join_permit(
|
||||
nonce: Nonce,
|
||||
family_head: FamilyHead,
|
||||
proxy: Option<Addr>,
|
||||
member_node: IdentityKey,
|
||||
) -> SignableFamilyJoinPermitMsg {
|
||||
let payload = FamilyJoinPermit::new(family_head, proxy, member_node);
|
||||
let payload = FamilyJoinPermit::new(family_head, member_node);
|
||||
|
||||
// note: we're NOT wrapping it in `ContractMessageContent` because the family head is not going to be the one
|
||||
// sending the message to the contract
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
|
||||
use crate::error::MixnetContractError;
|
||||
use crate::Layer;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Addr;
|
||||
use cosmwasm_std::Coin;
|
||||
use cosmwasm_std::{Addr, Uint128};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Index;
|
||||
|
||||
// type aliases for better reasoning about available data
|
||||
@@ -15,6 +17,65 @@ pub type SphinxKeyRef<'a> = &'a str;
|
||||
pub type MixId = u32;
|
||||
pub type BlockHeight = u64;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RangedValue<T> {
|
||||
pub minimum: T,
|
||||
pub maximum: T,
|
||||
}
|
||||
|
||||
impl<T> Copy for RangedValue<T> where T: Copy {}
|
||||
|
||||
pub type ProfitMarginRange = RangedValue<Percent>;
|
||||
pub type OperatingCostRange = RangedValue<Uint128>;
|
||||
|
||||
impl<T> Display for RangedValue<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} - {}", self.minimum, self.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProfitMarginRange {
|
||||
fn default() -> Self {
|
||||
ProfitMarginRange {
|
||||
minimum: Percent::zero(),
|
||||
maximum: Percent::hundred(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OperatingCostRange {
|
||||
fn default() -> Self {
|
||||
OperatingCostRange {
|
||||
minimum: Uint128::zero(),
|
||||
|
||||
// 1 billion (native tokens, i.e. 1 billion * 1'000'000 base tokens) - the total supply
|
||||
maximum: Uint128::new(1_000_000_000_000_000),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangedValue<T>
|
||||
where
|
||||
T: Copy + PartialOrd + PartialEq,
|
||||
{
|
||||
pub fn normalise(&self, value: T) -> T {
|
||||
if value < self.minimum {
|
||||
self.minimum
|
||||
} else if value > self.maximum {
|
||||
self.maximum
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
pub fn within_range(&self, value: T) -> bool {
|
||||
value >= self.minimum && value <= self.maximum
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies layer assignment for the given mixnode.
|
||||
#[cw_serde]
|
||||
pub struct LayerAssignment {
|
||||
@@ -154,4 +215,14 @@ pub struct ContractStateParams {
|
||||
|
||||
/// Minimum amount a gateway must pledge to get into the system.
|
||||
pub minimum_gateway_pledge: Coin,
|
||||
|
||||
/// Defines the allowed profit margin range of operators.
|
||||
/// default: 0% - 100%
|
||||
#[serde(default)]
|
||||
pub profit_margin: ProfitMarginRange,
|
||||
|
||||
/// Defines the allowed interval operating cost range of operators.
|
||||
/// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)
|
||||
#[serde(default)]
|
||||
pub interval_operating_cost: OperatingCostRange,
|
||||
}
|
||||
|
||||
@@ -167,3 +167,11 @@ pub fn new_track_undelegation_event() -> Event {
|
||||
pub fn new_track_reward_event() -> Event {
|
||||
Event::new(TRACK_REWARD_EVENT_TYPE)
|
||||
}
|
||||
|
||||
pub fn new_track_migrate_mixnode_event() -> Event {
|
||||
Event::new("track_migrate_vesting_mixnode")
|
||||
}
|
||||
|
||||
pub fn new_track_migrate_delegation_event() -> Event {
|
||||
Event::new("track_migrate_vesting_delegation")
|
||||
}
|
||||
|
||||
@@ -136,6 +136,14 @@ pub enum ExecuteMsg {
|
||||
address: String,
|
||||
cap: PledgeCap,
|
||||
},
|
||||
TrackMigratedMixnode {
|
||||
owner: String,
|
||||
},
|
||||
// no need to track migrated gateways as there are no vesting gateways on mainnet
|
||||
TrackMigratedDelegation {
|
||||
owner: String,
|
||||
mix_id: MixId,
|
||||
},
|
||||
}
|
||||
|
||||
impl ExecuteMsg {
|
||||
@@ -171,6 +179,10 @@ impl ExecuteMsg {
|
||||
ExecuteMsg::TransferOwnership { .. } => "VestingExecuteMsg::TransferOwnership",
|
||||
ExecuteMsg::UpdateStakingAddress { .. } => "VestingExecuteMsg::UpdateStakingAddress",
|
||||
ExecuteMsg::UpdateLockedPledgeCap { .. } => "VestingExecuteMsg::UpdateLockedPledgeCap",
|
||||
ExecuteMsg::TrackMigratedMixnode { .. } => "VestingExecuteMsg::TrackMigratedMixnode",
|
||||
ExecuteMsg::TrackMigratedDelegation { .. } => {
|
||||
"VestingExecuteMsg::TrackMigratedDelegation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ CREATE TABLE ecash_ticketbook
|
||||
-- introduce a way for us to introduce breaking changes in serialization of data
|
||||
serialization_revision INTEGER NOT NULL,
|
||||
|
||||
-- the type of the associated ticketbook
|
||||
ticketbook_type TEXT NOT NULL,
|
||||
|
||||
-- the actual crypto data of the ticketbook (wallet, keys, etc.)
|
||||
ticketbook_data BLOB NOT NULL UNIQUE,
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@ impl MemoryEcachTicketbookManager {
|
||||
.map(|t| BasicTicketbookInformation {
|
||||
id: t.ticketbook_id,
|
||||
expiration_date: t.ticketbook.expiration_date(),
|
||||
ticketbook_type: t.ticketbook.ticketbook_type().to_string(),
|
||||
epoch_id: t.ticketbook.epoch_id() as u32,
|
||||
total_tickets: t.ticketbook.spent_tickets() as u32,
|
||||
used_tickets: t.ticketbook.params_total_tickets() as u32,
|
||||
|
||||
@@ -61,11 +61,13 @@ impl SqliteEcashTicketbookManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn insert_new_ticketbook(
|
||||
&self,
|
||||
serialisation_revision: u8,
|
||||
data: &[u8],
|
||||
expiration_date: Date,
|
||||
typ: &str,
|
||||
epoch_id: u32,
|
||||
total_tickets: u32,
|
||||
used_tickets: u32,
|
||||
@@ -73,12 +75,13 @@ impl SqliteEcashTicketbookManager {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO ecash_ticketbook
|
||||
(serialization_revision, ticketbook_data, expiration_date, epoch_id, total_tickets, used_tickets)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
(serialization_revision, ticketbook_data, expiration_date, ticketbook_type, epoch_id, total_tickets, used_tickets)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
serialisation_revision,
|
||||
data,
|
||||
expiration_date,
|
||||
typ,
|
||||
epoch_id,
|
||||
total_tickets,
|
||||
used_tickets,
|
||||
@@ -92,7 +95,7 @@ impl SqliteEcashTicketbookManager {
|
||||
) -> Result<Vec<BasicTicketbookInformation>, sqlx::Error> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, expiration_date, epoch_id, total_tickets, used_tickets
|
||||
SELECT id, expiration_date, ticketbook_type, epoch_id, total_tickets, used_tickets
|
||||
FROM ecash_ticketbook
|
||||
"#,
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ pub struct RetrievedPendingTicketbook {
|
||||
pub struct BasicTicketbookInformation {
|
||||
pub id: i64,
|
||||
pub expiration_date: Date,
|
||||
pub ticketbook_type: String,
|
||||
pub epoch_id: u32,
|
||||
pub total_tickets: u32,
|
||||
pub used_tickets: u32,
|
||||
@@ -31,6 +32,8 @@ pub struct StoredIssuedTicketbook {
|
||||
|
||||
pub serialization_revision: u8,
|
||||
|
||||
pub ticketbook_type: String,
|
||||
|
||||
pub ticketbook_data: Vec<u8>,
|
||||
|
||||
#[zeroize(skip)]
|
||||
|
||||
@@ -114,6 +114,7 @@ impl Storage for PersistentStorage {
|
||||
serialisation_revision,
|
||||
&data,
|
||||
ticketbook.expiration_date(),
|
||||
&ticketbook.ticketbook_type().to_string(),
|
||||
ticketbook.epoch_id() as u32,
|
||||
ticketbook.params_total_tickets() as u32,
|
||||
ticketbook.spent_tickets() as u32,
|
||||
|
||||
@@ -14,9 +14,9 @@ time.workspace = true
|
||||
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credentials-interface = { path = "../../common/credentials-interface" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage", features = ["persistent-storage"] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-client-core = { path = "../../common/client-core" }
|
||||
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" }
|
||||
nym-ecash-time = { path = "../../common/ecash-time" }
|
||||
@@ -1,3 +1,6 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::errors::{Error, Result};
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::acquire::{
|
||||
@@ -7,6 +10,7 @@ use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use nym_config::DEFAULT_DATA_DIR;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_ecash_time::ecash_default_expiration_date;
|
||||
use nym_validator_client::coconut::all_ecash_api_clients;
|
||||
use nym_validator_client::nyxd::contract_traits::{
|
||||
@@ -16,7 +20,12 @@ use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub async fn issue_credential<C, S>(client: &C, storage: &S, client_id: &[u8]) -> Result<()>
|
||||
pub async fn issue_credential<C, S>(
|
||||
client: &C,
|
||||
storage: &S,
|
||||
client_id: &[u8],
|
||||
typ: TicketType,
|
||||
) -> Result<()>
|
||||
where
|
||||
C: DkgQueryClient + EcashSigningClient + EcashQueryClient + Send + Sync,
|
||||
S: Storage,
|
||||
@@ -49,6 +58,7 @@ where
|
||||
client,
|
||||
client_id,
|
||||
Some(ticketbook_expiration),
|
||||
typ,
|
||||
)
|
||||
.await?;
|
||||
info!("Deposit done");
|
||||
@@ -65,7 +75,7 @@ where
|
||||
}).map_err(Error::storage_error)?
|
||||
}
|
||||
|
||||
info!("Succeeded adding a ticketbook");
|
||||
info!("Succeeded adding a ticketbook of type '{typ}'");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -14,8 +14,10 @@ license.workspace = true
|
||||
bls12_381 = { workspace = true, default-features = false }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true, features = ["serde"] }
|
||||
rand = { workspace = true }
|
||||
|
||||
nym-compact-ecash = { path = "../nym_offline_compact_ecash" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_network_defaults::TicketTypeRepr;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use time::{Date, OffsetDateTime};
|
||||
|
||||
pub use nym_compact_ecash::{
|
||||
@@ -15,7 +17,6 @@ pub use nym_compact_ecash::{
|
||||
PartialCoinIndexSignature,
|
||||
},
|
||||
scheme::expiration_date_signatures::aggregate_expiration_signatures,
|
||||
scheme::expiration_date_signatures::date_scalar,
|
||||
scheme::expiration_date_signatures::{
|
||||
AnnotatedExpirationDateSignature, ExpirationDateSignature, ExpirationDateSignatureShare,
|
||||
PartialExpirationDateSignature,
|
||||
@@ -24,10 +25,10 @@ pub use nym_compact_ecash::{
|
||||
scheme::withdrawal::RequestInfo,
|
||||
scheme::Payment,
|
||||
scheme::{Wallet, WalletSignatures},
|
||||
withdrawal_request, Base58, BlindedSignature, Bytable, PartialWallet, PayInfo, PublicKeyUser,
|
||||
SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
|
||||
withdrawal_request, Base58, BlindedSignature, Bytable, EncodedDate, EncodedTicketType,
|
||||
PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
|
||||
};
|
||||
use nym_ecash_time::EcashTime;
|
||||
use nym_ecash_time::{ecash_today, EcashTime};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CredentialSigningData {
|
||||
@@ -38,6 +39,8 @@ pub struct CredentialSigningData {
|
||||
pub ecash_pub_key: PublicKeyUser,
|
||||
|
||||
pub expiration_date: Date,
|
||||
|
||||
pub ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
@@ -58,7 +61,7 @@ impl CredentialSpendingData {
|
||||
self.payment.spend_verify(
|
||||
verification_key,
|
||||
&self.pay_info,
|
||||
date_scalar(self.spend_date.ecash_unix_timestamp()),
|
||||
self.spend_date.ecash_unix_timestamp(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -216,3 +219,112 @@ impl From<PayInfo> for NymPayInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
strum::Display,
|
||||
strum::EnumString,
|
||||
)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum TicketType {
|
||||
#[default]
|
||||
V1MixnetEntry,
|
||||
V1MixnetExit,
|
||||
V1WireguardEntry,
|
||||
V1WireguardExit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Error)]
|
||||
#[error("provided unknown ticketbook type")]
|
||||
pub struct UnknownTicketType;
|
||||
|
||||
impl TicketType {
|
||||
pub fn to_repr(&self) -> TicketTypeRepr {
|
||||
(*self).into()
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> EncodedTicketType {
|
||||
self.to_repr() as EncodedTicketType
|
||||
}
|
||||
|
||||
pub fn try_from_encoded(val: EncodedTicketType) -> Result<Self, UnknownTicketType> {
|
||||
match val {
|
||||
n if n == TicketTypeRepr::V1MixnetEntry as u8 => {
|
||||
Ok(TicketTypeRepr::V1MixnetEntry.into())
|
||||
}
|
||||
n if n == TicketTypeRepr::V1MixnetExit as u8 => Ok(TicketTypeRepr::V1MixnetExit.into()),
|
||||
n if n == TicketTypeRepr::V1WireguardEntry as u8 => {
|
||||
Ok(TicketTypeRepr::V1WireguardEntry.into())
|
||||
}
|
||||
n if n == TicketTypeRepr::V1WireguardExit as u8 => {
|
||||
Ok(TicketTypeRepr::V1WireguardExit.into())
|
||||
}
|
||||
_ => Err(UnknownTicketType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TicketType> for TicketTypeRepr {
|
||||
fn from(value: TicketType) -> Self {
|
||||
match value {
|
||||
TicketType::V1MixnetEntry => TicketTypeRepr::V1MixnetEntry,
|
||||
TicketType::V1MixnetExit => TicketTypeRepr::V1MixnetExit,
|
||||
TicketType::V1WireguardEntry => TicketTypeRepr::V1WireguardEntry,
|
||||
TicketType::V1WireguardExit => TicketTypeRepr::V1WireguardExit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TicketTypeRepr> for TicketType {
|
||||
fn from(value: TicketTypeRepr) -> Self {
|
||||
match value {
|
||||
TicketTypeRepr::V1MixnetEntry => TicketType::V1MixnetEntry,
|
||||
TicketTypeRepr::V1MixnetExit => TicketType::V1MixnetExit,
|
||||
TicketTypeRepr::V1WireguardEntry => TicketType::V1WireguardEntry,
|
||||
TicketTypeRepr::V1WireguardExit => TicketType::V1WireguardExit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientTicket {
|
||||
pub spending_data: CredentialSpendingData,
|
||||
pub ticket_id: i64,
|
||||
}
|
||||
|
||||
impl ClientTicket {
|
||||
pub fn new(spending_data: CredentialSpendingData, ticket_id: i64) -> Self {
|
||||
ClientTicket {
|
||||
spending_data,
|
||||
ticket_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct AvailableBandwidth {
|
||||
pub bytes: i64,
|
||||
pub expiration: OffsetDateTime,
|
||||
}
|
||||
|
||||
impl AvailableBandwidth {
|
||||
pub fn expired(&self) -> bool {
|
||||
self.expiration < ecash_today()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AvailableBandwidth {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bytes: 0,
|
||||
expiration: OffsetDateTime::UNIX_EPOCH,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::ecash::bandwidth::issued::IssuedTicketBook;
|
||||
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
|
||||
use crate::ecash::bandwidth::CredentialSigningData;
|
||||
use crate::ecash::utils::cred_exp_date;
|
||||
use crate::error::Error;
|
||||
use nym_api_requests::ecash::BlindSignRequestBody;
|
||||
use nym_credentials_interface::{
|
||||
aggregate_wallets, generate_keypair_user_from_seed, issue_verify, withdrawal_request,
|
||||
BlindedSignature, KeyPairUser, PartialWallet, VerificationKeyAuth, WalletSignatures,
|
||||
WithdrawalRequest,
|
||||
BlindedSignature, KeyPairUser, PartialWallet, TicketType, VerificationKeyAuth,
|
||||
WalletSignatures, WithdrawalRequest,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_ecash_contract_common::deposit::DepositId;
|
||||
@@ -18,7 +19,6 @@ use nym_validator_client::nym_api::EpochId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::Date;
|
||||
|
||||
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
|
||||
pub use nym_validator_client::nyxd::{Coin, Hash};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -32,6 +32,9 @@ pub struct IssuanceTicketBook {
|
||||
/// ecash keypair related to the credential
|
||||
ecash_keypair: KeyPairUser,
|
||||
|
||||
/// the type of the ticketbook to be issued
|
||||
ticketbook_type: TicketType,
|
||||
|
||||
/// expiration_date of that credential
|
||||
expiration_date: Date,
|
||||
}
|
||||
@@ -41,12 +44,14 @@ impl IssuanceTicketBook {
|
||||
deposit_id: DepositId,
|
||||
identifier: M,
|
||||
signing_key: identity::PrivateKey,
|
||||
ticketbook_type: TicketType,
|
||||
) -> Self {
|
||||
//this expiration date will get fed to the ecash library, force midnight to be set
|
||||
Self::new_with_expiration(
|
||||
deposit_id,
|
||||
identifier,
|
||||
signing_key,
|
||||
ticketbook_type,
|
||||
ecash_default_expiration_date(),
|
||||
)
|
||||
}
|
||||
@@ -55,6 +60,7 @@ impl IssuanceTicketBook {
|
||||
deposit_id: DepositId,
|
||||
identifier: M,
|
||||
signing_key: identity::PrivateKey,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
) -> Self {
|
||||
let ecash_keypair = generate_keypair_user_from_seed(identifier);
|
||||
@@ -62,6 +68,7 @@ impl IssuanceTicketBook {
|
||||
deposit_id,
|
||||
signing_key,
|
||||
ecash_keypair,
|
||||
ticketbook_type,
|
||||
expiration_date,
|
||||
}
|
||||
}
|
||||
@@ -76,6 +83,10 @@ impl IssuanceTicketBook {
|
||||
self.expiration_date
|
||||
}
|
||||
|
||||
pub fn ticketbook_type(&self) -> TicketType {
|
||||
self.ticketbook_type
|
||||
}
|
||||
|
||||
pub fn request_plaintext(request: &WithdrawalRequest, deposit_id: DepositId) -> Vec<u8> {
|
||||
let mut message = request.to_bytes();
|
||||
message.extend_from_slice(&deposit_id.to_be_bytes());
|
||||
@@ -99,6 +110,7 @@ impl IssuanceTicketBook {
|
||||
request_signature,
|
||||
signing_request.ecash_pub_key.clone(),
|
||||
signing_request.expiration_date,
|
||||
signing_request.ticketbook_type,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -133,6 +145,7 @@ impl IssuanceTicketBook {
|
||||
let (withdrawal_request, request_info) = withdrawal_request(
|
||||
self.ecash_keypair.secret_key(),
|
||||
self.expiration_date.ecash_unix_timestamp(),
|
||||
self.ticketbook_type.encode(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -141,6 +154,7 @@ impl IssuanceTicketBook {
|
||||
request_info,
|
||||
ecash_pub_key: self.ecash_keypair.public_key(),
|
||||
expiration_date: self.expiration_date,
|
||||
ticketbook_type: self.ticketbook_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +232,7 @@ impl IssuanceTicketBook {
|
||||
wallet,
|
||||
epoch_id,
|
||||
self.ecash_keypair.secret_key().clone(),
|
||||
self.ticketbook_type,
|
||||
self.expiration_date,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::ecash::bandwidth::CredentialSpendingData;
|
||||
use crate::ecash::utils::ecash_today;
|
||||
use crate::error::Error;
|
||||
use nym_credentials_interface::{
|
||||
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, VerificationKeyAuth,
|
||||
Wallet, WalletSignatures,
|
||||
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, TicketType,
|
||||
VerificationKeyAuth, Wallet, WalletSignatures,
|
||||
};
|
||||
use nym_ecash_time::EcashTime;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -36,6 +36,10 @@ pub struct IssuedTicketBook {
|
||||
/// expiration_date for easier discarding
|
||||
#[zeroize(skip)]
|
||||
expiration_date: Date,
|
||||
|
||||
/// the type of the ticketbook to got issued
|
||||
#[zeroize(skip)]
|
||||
ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
impl IssuedTicketBook {
|
||||
@@ -43,6 +47,7 @@ impl IssuedTicketBook {
|
||||
wallet: WalletSignatures,
|
||||
epoch_id: EpochId,
|
||||
ecash_secret_key: SecretKeyUser,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
) -> Self {
|
||||
IssuedTicketBook {
|
||||
@@ -51,6 +56,7 @@ impl IssuedTicketBook {
|
||||
epoch_id,
|
||||
ecash_secret_key,
|
||||
expiration_date,
|
||||
ticketbook_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +64,7 @@ impl IssuedTicketBook {
|
||||
signatures_wallet: WalletSignatures,
|
||||
epoch_id: EpochId,
|
||||
ecash_secret_key: SecretKeyUser,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
spent_tickets: u64,
|
||||
) -> Self {
|
||||
@@ -67,6 +74,7 @@ impl IssuedTicketBook {
|
||||
epoch_id,
|
||||
ecash_secret_key,
|
||||
expiration_date,
|
||||
ticketbook_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +86,10 @@ impl IssuedTicketBook {
|
||||
self.epoch_id
|
||||
}
|
||||
|
||||
pub fn ticketbook_type(&self) -> TicketType {
|
||||
self.ticketbook_type
|
||||
}
|
||||
|
||||
pub fn current_serialization_revision(&self) -> u8 {
|
||||
CURRENT_SERIALIZATION_REVISION
|
||||
}
|
||||
|
||||
@@ -36,22 +36,6 @@ pub fn aggregate_verification_keys(
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn obtain_aggregated_verification_key(
|
||||
_api_clients: &[EcashApiClient],
|
||||
) -> Result<VerificationKeyAuth, Error> {
|
||||
// TODO:
|
||||
// let total = api_clients.len();
|
||||
// let mut rng = thread_rng();
|
||||
// let indices = sample(&mut rng, total, total);
|
||||
// for index in indices {
|
||||
// // randomly try apis until we succeed
|
||||
// // if let Ok(res) = api_clients[index].api_client.get_aggregated_verification_key().await {
|
||||
// // //
|
||||
// // }
|
||||
// }
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn obtain_expiration_date_signatures(
|
||||
ecash_api_clients: &[EcashApiClient],
|
||||
verification_key: &VerificationKeyAuth,
|
||||
@@ -63,7 +47,7 @@ pub async fn obtain_expiration_date_signatures(
|
||||
|
||||
let mut signatures_shares: Vec<_> = Vec::with_capacity(ecash_api_clients.len());
|
||||
|
||||
let expiration_date = cred_exp_date().unix_timestamp() as u64;
|
||||
let expiration_date = cred_exp_date().ecash_unix_timestamp();
|
||||
for ecash_api_client in ecash_api_clients.iter() {
|
||||
match ecash_api_client
|
||||
.api_client
|
||||
|
||||
@@ -6,13 +6,16 @@ use time::{Duration, PrimitiveDateTime, Time};
|
||||
pub use time::{Date, OffsetDateTime};
|
||||
|
||||
pub trait EcashTime {
|
||||
fn ecash_unix_timestamp(&self) -> u64 {
|
||||
fn ecash_unix_timestamp(&self) -> u32 {
|
||||
let ts = self.ecash_datetime().unix_timestamp();
|
||||
|
||||
// just panic on pre-1970 timestamps...
|
||||
assert!(ts > 0);
|
||||
|
||||
ts as u64
|
||||
// and on anything in 22nd century...
|
||||
assert!(ts <= u32::MAX as i64);
|
||||
|
||||
ts as u32
|
||||
}
|
||||
|
||||
fn ecash_date(&self) -> Date {
|
||||
|
||||
@@ -21,12 +21,12 @@ thiserror = { workspace = true }
|
||||
tracing = { workspace = true, features = ["log"] }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credentials-interface = { path = "../../common/credentials-interface" }
|
||||
nym-credentials = { path = "../credentials" }
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
|
||||
workspace = true
|
||||
@@ -41,6 +41,4 @@ workspace = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" } # we need specific imports in tests
|
||||
|
||||
|
||||
nym-compact-ecash = { path = "../nym_offline_compact_ecash" } # we need specific imports in tests
|
||||
@@ -64,6 +64,7 @@ mod tests {
|
||||
};
|
||||
use nym_credentials::ecash::utils::EcashTime;
|
||||
use nym_credentials::IssuanceTicketBook;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
@@ -75,7 +76,7 @@ mod tests {
|
||||
let mut rng = OsRng;
|
||||
let signing_key = ed25519::PrivateKey::new(&mut rng);
|
||||
|
||||
let issuance = IssuanceTicketBook::new(42, [], signing_key);
|
||||
let issuance = IssuanceTicketBook::new(42, [], signing_key, TicketType::V1MixnetEntry);
|
||||
let expiration_date = issuance.expiration_date();
|
||||
let sig_req = issuance.prepare_for_signing();
|
||||
let exp_date_sigs = generate_expiration_date_signatures(
|
||||
@@ -91,6 +92,7 @@ mod tests {
|
||||
sig_req.ecash_pub_key.clone(),
|
||||
&sig_req.withdrawal_request,
|
||||
expiration_date.ecash_unix_timestamp(),
|
||||
issuance.ticketbook_type().encode(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
[package]
|
||||
name = "nym-gateway-storage"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
bincode = { workspace = true, optional = true }
|
||||
defguard_wireguard_rs = { workspace = true, optional = true }
|
||||
log = { workspace = true }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
"time",
|
||||
] }
|
||||
time = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
nym-gateway-requests = { path = "../gateway-requests" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
|
||||
[features]
|
||||
wireguard = ["defguard_wireguard_rs", "bincode"]
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
CREATE TABLE wireguard_peer
|
||||
(
|
||||
public_key TEXT NOT NULL PRIMARY KEY UNIQUE,
|
||||
preshared_key TEXT,
|
||||
protocol_version INTEGER,
|
||||
endpoint TEXT,
|
||||
last_handshake TIMESTAMP,
|
||||
tx_bytes BIGINT NOT NULL,
|
||||
rx_bytes BIGINT NOT NULL,
|
||||
persistent_keepalive_interval INTEGER,
|
||||
allowed_ips BLOB NOT NULL,
|
||||
suspended BOOLEAN NOT NULL
|
||||
);
|
||||
@@ -1,11 +1,28 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::storage::models::PersistedBandwidth;
|
||||
use crate::models::PersistedBandwidth;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct AvailableBandwidth {
|
||||
pub bytes: i64,
|
||||
pub freepass_expiration: Option<OffsetDateTime>,
|
||||
}
|
||||
|
||||
impl AvailableBandwidth {
|
||||
pub fn freepass_expired(&self) -> bool {
|
||||
if let Some(expiration) = self.freepass_expiration {
|
||||
if expiration < OffsetDateTime::now_utc() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BandwidthManager {
|
||||
pub struct BandwidthManager {
|
||||
connection_pool: sqlx::SqlitePool,
|
||||
}
|
||||
|
||||
@@ -15,7 +32,7 @@ impl BandwidthManager {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `connection_pool`: database connection pool to use.
|
||||
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
||||
pub fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
||||
BandwidthManager { connection_pool }
|
||||
}
|
||||
|
||||
@@ -16,4 +16,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("the stored data associated with ticket {ticket_id} is malformed!")]
|
||||
MalformedStoredTicketData { ticket_id: i64 },
|
||||
|
||||
#[error("Failed to convert from type of database: {0}")]
|
||||
TypeConversion(String),
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::storage::models::StoredMessage;
|
||||
use crate::models::StoredMessage;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct InboxManager {
|
||||
@@ -1,29 +1,32 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::client_handling::websocket::connection_handler::ecash::ClientTicket;
|
||||
use crate::node::storage::bandwidth::BandwidthManager;
|
||||
use crate::node::storage::error::StorageError;
|
||||
use crate::node::storage::inboxes::InboxManager;
|
||||
use crate::node::storage::models::{
|
||||
PersistedBandwidth, PersistedSharedKeys, RedemptionProposal, StoredMessage, VerifiedTicket,
|
||||
};
|
||||
use crate::node::storage::shared_keys::SharedKeysManager;
|
||||
use crate::node::storage::tickets::TicketStorageManager;
|
||||
use async_trait::async_trait;
|
||||
use bandwidth::BandwidthManager;
|
||||
use error::StorageError;
|
||||
use inboxes::InboxManager;
|
||||
use models::{
|
||||
PersistedBandwidth, PersistedSharedKeys, RedemptionProposal, StoredMessage, VerifiedTicket,
|
||||
WireguardPeer,
|
||||
};
|
||||
use nym_credentials_interface::ClientTicket;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use shared_keys::SharedKeysManager;
|
||||
use sqlx::ConnectOptions;
|
||||
use std::path::Path;
|
||||
use tickets::TicketStorageManager;
|
||||
use time::OffsetDateTime;
|
||||
use tracing::{debug, error};
|
||||
|
||||
mod bandwidth;
|
||||
pub(crate) mod error;
|
||||
pub mod bandwidth;
|
||||
pub mod error;
|
||||
mod inboxes;
|
||||
pub(crate) mod models;
|
||||
mod shared_keys;
|
||||
mod tickets;
|
||||
#[cfg(feature = "wireguard")]
|
||||
mod wireguard_peers;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Storage: Send + Sync {
|
||||
@@ -207,6 +210,42 @@ pub trait Storage: Send + Sync {
|
||||
async fn get_votes(&self, ticket_id: i64) -> Result<Vec<i64>, StorageError>;
|
||||
|
||||
async fn get_signers(&self, epoch_id: i64) -> Result<Vec<i64>, StorageError>;
|
||||
|
||||
/// Insert a wireguard peer in the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer`: wireguard peer data to be stored
|
||||
/// * `suspended`: if peer exists, but it's currently suspended
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn insert_wireguard_peer(
|
||||
&self,
|
||||
peer: &defguard_wireguard_rs::host::Peer,
|
||||
suspended: bool,
|
||||
) -> Result<(), StorageError>;
|
||||
|
||||
/// Tries to retrieve available bandwidth for the particular peer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer_public_key`: wireguard public key of the peer to be retrieved.
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_wireguard_peer(
|
||||
&self,
|
||||
peer_public_key: &str,
|
||||
) -> Result<Option<WireguardPeer>, StorageError>;
|
||||
|
||||
/// Retrieves all wireguard peers.
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_all_wireguard_peers(&self) -> Result<Vec<WireguardPeer>, StorageError>;
|
||||
|
||||
/// Remove a wireguard peer from the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer_public_key`: wireguard public key of the peer to be removed.
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn remove_wireguard_peer(&self, peer_public_key: &str) -> Result<(), StorageError>;
|
||||
}
|
||||
|
||||
// note that clone here is fine as upon cloning the same underlying pool will be used
|
||||
@@ -216,6 +255,8 @@ pub struct PersistentStorage {
|
||||
inbox_manager: InboxManager,
|
||||
bandwidth_manager: BandwidthManager,
|
||||
ticket_manager: TicketStorageManager,
|
||||
#[cfg(feature = "wireguard")]
|
||||
wireguard_peer_manager: wireguard_peers::WgPeerManager,
|
||||
}
|
||||
|
||||
impl PersistentStorage {
|
||||
@@ -259,6 +300,8 @@ impl PersistentStorage {
|
||||
|
||||
// the cloning here are cheap as connection pool is stored behind an Arc
|
||||
Ok(PersistentStorage {
|
||||
#[cfg(feature = "wireguard")]
|
||||
wireguard_peer_manager: wireguard_peers::WgPeerManager::new(connection_pool.clone()),
|
||||
shared_key_manager: SharedKeysManager::new(connection_pool.clone()),
|
||||
inbox_manager: InboxManager::new(connection_pool.clone(), message_retrieval_limit),
|
||||
bandwidth_manager: BandwidthManager::new(connection_pool.clone()),
|
||||
@@ -576,4 +619,42 @@ impl Storage for PersistentStorage {
|
||||
async fn get_signers(&self, epoch_id: i64) -> Result<Vec<i64>, StorageError> {
|
||||
Ok(self.ticket_manager.get_epoch_signers(epoch_id).await?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn insert_wireguard_peer(
|
||||
&self,
|
||||
peer: &defguard_wireguard_rs::host::Peer,
|
||||
suspended: bool,
|
||||
) -> Result<(), StorageError> {
|
||||
let mut peer = WireguardPeer::from(peer.clone());
|
||||
peer.suspended = suspended;
|
||||
self.wireguard_peer_manager.insert_peer(&peer).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_wireguard_peer(
|
||||
&self,
|
||||
peer_public_key: &str,
|
||||
) -> Result<Option<WireguardPeer>, StorageError> {
|
||||
let peer = self
|
||||
.wireguard_peer_manager
|
||||
.retrieve_peer(peer_public_key)
|
||||
.await?;
|
||||
Ok(peer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_all_wireguard_peers(&self) -> Result<Vec<WireguardPeer>, StorageError> {
|
||||
let ret = self.wireguard_peer_manager.retrieve_all_peers().await?;
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn remove_wireguard_peer(&self, peer_public_key: &str) -> Result<(), StorageError> {
|
||||
self.wireguard_peer_manager
|
||||
.remove_peer(peer_public_key)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::error::StorageError;
|
||||
use nym_credentials_interface::{AvailableBandwidth, ClientTicket, CredentialSpendingData};
|
||||
use sqlx::FromRow;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub struct PersistedSharedKeys {
|
||||
#[allow(dead_code)]
|
||||
pub id: i64,
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub client_address_bs58: String,
|
||||
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
|
||||
}
|
||||
|
||||
pub struct StoredMessage {
|
||||
pub id: i64,
|
||||
#[allow(dead_code)]
|
||||
pub client_address_bs58: String,
|
||||
pub content: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
pub struct PersistedBandwidth {
|
||||
#[allow(dead_code)]
|
||||
pub client_id: i64,
|
||||
pub available: i64,
|
||||
pub expiration: Option<OffsetDateTime>,
|
||||
}
|
||||
|
||||
impl From<PersistedBandwidth> for AvailableBandwidth {
|
||||
fn from(value: PersistedBandwidth) -> Self {
|
||||
AvailableBandwidth {
|
||||
bytes: value.available,
|
||||
expiration: value.expiration.unwrap_or(OffsetDateTime::UNIX_EPOCH),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct VerifiedTicket {
|
||||
pub serial_number: Vec<u8>,
|
||||
pub ticket_id: i64,
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct RedemptionProposal {
|
||||
pub proposal_id: i64,
|
||||
pub created_at: OffsetDateTime,
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct UnverifiedTicketData {
|
||||
pub data: Vec<u8>,
|
||||
pub ticket_id: i64,
|
||||
}
|
||||
|
||||
impl TryFrom<UnverifiedTicketData> for ClientTicket {
|
||||
type Error = StorageError;
|
||||
|
||||
fn try_from(value: UnverifiedTicketData) -> Result<Self, Self::Error> {
|
||||
Ok(ClientTicket {
|
||||
spending_data: CredentialSpendingData::try_from_bytes(&value.data).map_err(|_| {
|
||||
StorageError::MalformedStoredTicketData {
|
||||
ticket_id: value.ticket_id,
|
||||
}
|
||||
})?,
|
||||
ticket_id: value.ticket_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
pub struct WireguardPeer {
|
||||
pub public_key: String,
|
||||
pub preshared_key: Option<String>,
|
||||
pub protocol_version: Option<i64>,
|
||||
pub endpoint: Option<String>,
|
||||
pub last_handshake: Option<sqlx::types::chrono::NaiveDateTime>,
|
||||
pub tx_bytes: i64,
|
||||
pub rx_bytes: i64,
|
||||
pub persistent_keepalive_interval: Option<i64>,
|
||||
pub allowed_ips: Vec<u8>,
|
||||
pub suspended: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
impl From<defguard_wireguard_rs::host::Peer> for WireguardPeer {
|
||||
fn from(value: defguard_wireguard_rs::host::Peer) -> Self {
|
||||
WireguardPeer {
|
||||
public_key: value.public_key.to_string(),
|
||||
preshared_key: value.preshared_key.as_ref().map(|k| k.to_string()),
|
||||
protocol_version: value.protocol_version.map(|v| v as i64),
|
||||
endpoint: value.endpoint.map(|e| e.to_string()),
|
||||
last_handshake: value.last_handshake.and_then(|t| {
|
||||
if let Ok(d) = t.duration_since(std::time::UNIX_EPOCH) {
|
||||
if let Ok(millis) = d.as_millis().try_into() {
|
||||
sqlx::types::chrono::DateTime::from_timestamp_millis(millis)
|
||||
.map(|d| d.naive_utc())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
tx_bytes: value.tx_bytes as i64,
|
||||
rx_bytes: value.rx_bytes as i64,
|
||||
persistent_keepalive_interval: value.persistent_keepalive_interval.map(|v| v as i64),
|
||||
allowed_ips: bincode::Options::serialize(
|
||||
bincode::DefaultOptions::new(),
|
||||
&value.allowed_ips,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
suspended: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
impl TryFrom<WireguardPeer> for defguard_wireguard_rs::host::Peer {
|
||||
type Error = crate::error::StorageError;
|
||||
|
||||
fn try_from(value: WireguardPeer) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
public_key: value
|
||||
.public_key
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("public key {e}")))?,
|
||||
preshared_key: value
|
||||
.preshared_key
|
||||
.as_deref()
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("preshared key {e}")))?,
|
||||
protocol_version: value
|
||||
.protocol_version
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("protocol version {e}")))?,
|
||||
endpoint: value
|
||||
.endpoint
|
||||
.as_deref()
|
||||
.map(|e| e.parse())
|
||||
.transpose()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("endpoint {e}")))?,
|
||||
last_handshake: value.last_handshake.and_then(|t| {
|
||||
let unix_time = std::time::UNIX_EPOCH;
|
||||
if let Ok(millis) = t.and_utc().timestamp_millis().try_into() {
|
||||
let duration = std::time::Duration::from_millis(millis);
|
||||
unix_time.checked_add(duration)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
tx_bytes: value
|
||||
.tx_bytes
|
||||
.try_into()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("tx bytes {e}")))?,
|
||||
rx_bytes: value
|
||||
.rx_bytes
|
||||
.try_into()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("rx bytes {e}")))?,
|
||||
persistent_keepalive_interval: value
|
||||
.persistent_keepalive_interval
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| {
|
||||
Self::Error::TypeConversion(format!("persistent keepalive interval {e}"))
|
||||
})?,
|
||||
allowed_ips: bincode::Options::deserialize(
|
||||
bincode::DefaultOptions::new(),
|
||||
&value.allowed_ips,
|
||||
)
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("allowed ips {e}")))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::storage::models::PersistedSharedKeys;
|
||||
use crate::models::PersistedSharedKeys;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct SharedKeysManager {
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::storage::models::{RedemptionProposal, UnverifiedTicketData, VerifiedTicket};
|
||||
use crate::models::{RedemptionProposal, UnverifiedTicketData, VerifiedTicket};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::models::WireguardPeer;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct WgPeerManager {
|
||||
connection_pool: sqlx::SqlitePool,
|
||||
}
|
||||
|
||||
impl WgPeerManager {
|
||||
/// Creates new instance of the `WgPeersManager` with the provided sqlite connection pool.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `connection_pool`: database connection pool to use.
|
||||
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
||||
WgPeerManager { connection_pool }
|
||||
}
|
||||
|
||||
/// Creates a new wireguard peer entry for its particular public key or
|
||||
/// overwrittes the peer entry data if it already existed.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer`: peer information needed by wireguard interface.
|
||||
pub(crate) async fn insert_peer(&self, peer: &WireguardPeer) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"INSERT OR REPLACE INTO wireguard_peer(public_key, preshared_key, protocol_version, endpoint, last_handshake, tx_bytes, rx_bytes, persistent_keepalive_interval, allowed_ips, suspended) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
peer.public_key, peer.preshared_key, peer.protocol_version, peer.endpoint, peer.last_handshake, peer.tx_bytes, peer.rx_bytes, peer.persistent_keepalive_interval, peer.allowed_ips, peer.suspended
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve the wireguard peer with the provided public key from the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `public_key`: the unique public key of the wireguard peer.
|
||||
pub(crate) async fn retrieve_peer(
|
||||
&self,
|
||||
public_key: &str,
|
||||
) -> Result<Option<WireguardPeer>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
WireguardPeer,
|
||||
r#"
|
||||
SELECT * FROM wireguard_peer
|
||||
WHERE public_key = ?
|
||||
LIMIT 1
|
||||
"#,
|
||||
public_key,
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Retrieve all wireguard peers.
|
||||
pub(crate) async fn retrieve_all_peers(&self) -> Result<Vec<WireguardPeer>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
WireguardPeer,
|
||||
r#"
|
||||
SELECT *
|
||||
FROM wireguard_peer;
|
||||
"#,
|
||||
)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Retrieve the wireguard peer with the provided public key from the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `public_key`: the unique public key of the wireguard peer.
|
||||
pub(crate) async fn remove_peer(&self, public_key: &str) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
DELETE FROM wireguard_peer
|
||||
WHERE public_key = ?
|
||||
"#,
|
||||
public_key,
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{v6, v7};
|
||||
|
||||
impl From<v7::response::StaticConnectFailureReason> for v6::response::StaticConnectFailureReason {
|
||||
fn from(failure: v7::response::StaticConnectFailureReason) -> Self {
|
||||
match failure {
|
||||
v7::response::StaticConnectFailureReason::RequestedIpAlreadyInUse => {
|
||||
v6::response::StaticConnectFailureReason::RequestedIpAlreadyInUse
|
||||
}
|
||||
v7::response::StaticConnectFailureReason::RequestedNymAddressAlreadyInUse => {
|
||||
v6::response::StaticConnectFailureReason::RequestedNymAddressAlreadyInUse
|
||||
}
|
||||
v7::response::StaticConnectFailureReason::OutOfDateTimestamp => {
|
||||
v6::response::StaticConnectFailureReason::Other("out of date timestamp".to_string())
|
||||
}
|
||||
v7::response::StaticConnectFailureReason::Other(reason) => {
|
||||
v6::response::StaticConnectFailureReason::Other(reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v7::response::DynamicConnectFailureReason> for v6::response::DynamicConnectFailureReason {
|
||||
fn from(failure: v7::response::DynamicConnectFailureReason) -> Self {
|
||||
match failure {
|
||||
v7::response::DynamicConnectFailureReason::RequestedNymAddressAlreadyInUse => {
|
||||
v6::response::DynamicConnectFailureReason::RequestedNymAddressAlreadyInUse
|
||||
}
|
||||
v7::response::DynamicConnectFailureReason::NoAvailableIp => {
|
||||
v6::response::DynamicConnectFailureReason::NoAvailableIp
|
||||
}
|
||||
v7::response::DynamicConnectFailureReason::Other(err) => {
|
||||
v6::response::DynamicConnectFailureReason::Other(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v7::response::InfoResponseReply> for v6::response::InfoResponseReply {
|
||||
fn from(reply: v7::response::InfoResponseReply) -> Self {
|
||||
match reply {
|
||||
v7::response::InfoResponseReply::Generic { msg } => {
|
||||
v6::response::InfoResponseReply::Generic { msg }
|
||||
}
|
||||
v7::response::InfoResponseReply::VersionMismatch {
|
||||
request_version,
|
||||
response_version,
|
||||
} => v6::response::InfoResponseReply::VersionMismatch {
|
||||
request_version,
|
||||
response_version,
|
||||
},
|
||||
v7::response::InfoResponseReply::ExitPolicyFilterCheckFailed { dst } => {
|
||||
v6::response::InfoResponseReply::ExitPolicyFilterCheckFailed { dst }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v7::response::InfoLevel> for v6::response::InfoLevel {
|
||||
fn from(level: v7::response::InfoLevel) -> Self {
|
||||
match level {
|
||||
v7::response::InfoLevel::Info => v6::response::InfoLevel::Info,
|
||||
v7::response::InfoLevel::Warn => v6::response::InfoLevel::Warn,
|
||||
v7::response::InfoLevel::Error => v6::response::InfoLevel::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod conversion;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user