Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e7200a7c8 | |||
| 3f0d4846df | |||
| 9bfcdbe8e2 | |||
| 8c4885ce2c | |||
| 926389df89 | |||
| b55db00408 | |||
| cfcb64f7e5 | |||
| 9c6c5f5170 | |||
| f28888e3e7 | |||
| 9549bed8bb | |||
| 7c65d61d91 | |||
| ad2efb7e62 | |||
| a50c9bfa1a | |||
| 30cdbf535a | |||
| f5365cbca9 | |||
| 22e7cb887b | |||
| b571f1a881 | |||
| b1c4e3ded7 | |||
| 4694ded8bd | |||
| 7971573026 | |||
| c4780c8af2 | |||
| 7879d76592 | |||
| 0f62ea25d8 | |||
| cde53c02e7 | |||
| de64da8e20 | |||
| 4aeac1acd2 | |||
| 679be24074 | |||
| 36e07f546d | |||
| d264feaf22 | |||
| 32b7b7afdc | |||
| 7a50f0c3b2 | |||
| 091382ef30 | |||
| 2da6a2fbfa | |||
| d910a4e0ee | |||
| 672ab79421 | |||
| 1ad97adc7c |
@@ -30,6 +30,7 @@ jobs:
|
|||||||
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
||||||
needs: matrix_prep
|
needs: matrix_prep
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -63,4 +64,4 @@ jobs:
|
|||||||
if: ${{ matrix.rust != 'nightly' }}
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --manifest-path contracts/Cargo.toml --workspace -- -D warnings
|
args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
|
||||||
|
|||||||
@@ -64,4 +64,4 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features -- -D warnings
|
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features --all-targets -- -D warnings
|
||||||
|
|||||||
@@ -4,6 +4,15 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- nym-network-statistics properly handles signals ([#3209])
|
||||||
|
- add socks5 support for Rust SDK ([#3226], [#3255])
|
||||||
|
- add coconut bandwidth credential support for Rust SDK ([#3273])
|
||||||
|
|
||||||
|
[#3209]: https://github.com/nymtech/nym/issues/3209
|
||||||
|
[#3226]: https://github.com/nymtech/nym/pull/3226
|
||||||
|
[#3255]: https://github.com/nymtech/nym/pull/3255
|
||||||
|
[#3273]: https://github.com/nymtech/nym/pull/3273
|
||||||
|
|
||||||
## [v1.1.15] (2023-04-18)
|
## [v1.1.15] (2023-04-18)
|
||||||
|
|
||||||
- Fix verloc being stuck waiting for shutdown signal ([#3250])
|
- Fix verloc being stuck waiting for shutdown signal ([#3250])
|
||||||
@@ -41,6 +50,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
[#3187]: https://github.com/nymtech/nym/issues/3187
|
[#3187]: https://github.com/nymtech/nym/issues/3187
|
||||||
[#3203]: https://github.com/nymtech/nym/pull/3203
|
[#3203]: https://github.com/nymtech/nym/pull/3203
|
||||||
[#3199]: https://github.com/nymtech/nym/pull/3199
|
[#3199]: https://github.com/nymtech/nym/pull/3199
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
## [v1.1.13] (2023-03-15)
|
## [v1.1.13] (2023-03-15)
|
||||||
|
|
||||||
|
|||||||
Generated
+58
-23
@@ -3031,6 +3031,7 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"nym-api-requests",
|
"nym-api-requests",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-bin-common",
|
"nym-bin-common",
|
||||||
"nym-coconut",
|
"nym-coconut",
|
||||||
"nym-coconut-bandwidth-contract-common",
|
"nym-coconut-bandwidth-contract-common",
|
||||||
@@ -3089,6 +3090,22 @@ dependencies = [
|
|||||||
"ts-rs",
|
"ts-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nym-bandwidth-controller"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bip39",
|
||||||
|
"nym-coconut-interface",
|
||||||
|
"nym-credential-storage",
|
||||||
|
"nym-credentials",
|
||||||
|
"nym-crypto",
|
||||||
|
"nym-network-defaults",
|
||||||
|
"nym-validator-client",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"thiserror",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-bin-common"
|
name = "nym-bin-common"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -3193,6 +3210,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-bin-common",
|
"nym-bin-common",
|
||||||
"nym-client-core",
|
"nym-client-core",
|
||||||
"nym-client-websocket-requests",
|
"nym-client-websocket-requests",
|
||||||
@@ -3201,7 +3219,6 @@ dependencies = [
|
|||||||
"nym-credential-storage",
|
"nym-credential-storage",
|
||||||
"nym-credentials",
|
"nym-credentials",
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-gateway-client",
|
|
||||||
"nym-gateway-requests",
|
"nym-gateway-requests",
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-pemstore",
|
"nym-pemstore",
|
||||||
@@ -3231,7 +3248,9 @@ dependencies = [
|
|||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"humantime-serde",
|
"humantime-serde",
|
||||||
"log",
|
"log",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-config",
|
"nym-config",
|
||||||
|
"nym-credential-storage",
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-gateway-client",
|
"nym-gateway-client",
|
||||||
"nym-gateway-requests",
|
"nym-gateway-requests",
|
||||||
@@ -3354,23 +3373,19 @@ dependencies = [
|
|||||||
name = "nym-credential-client"
|
name = "nym-credential-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bip39",
|
|
||||||
"clap 4.1.11",
|
"clap 4.1.11",
|
||||||
"log",
|
"log",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-bin-common",
|
"nym-bin-common",
|
||||||
"nym-coconut-interface",
|
|
||||||
"nym-config",
|
"nym-config",
|
||||||
"nym-credential-storage",
|
"nym-credential-storage",
|
||||||
"nym-credentials",
|
"nym-credentials",
|
||||||
"nym-crypto",
|
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-pemstore",
|
"nym-pemstore",
|
||||||
"nym-validator-client",
|
"nym-validator-client",
|
||||||
"rand 0.7.3",
|
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3507,16 +3522,14 @@ dependencies = [
|
|||||||
name = "nym-gateway-client"
|
name = "nym-gateway-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
|
||||||
"futures",
|
"futures",
|
||||||
"getrandom 0.2.8",
|
"getrandom 0.2.8",
|
||||||
"log",
|
"log",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-coconut-interface",
|
"nym-coconut-interface",
|
||||||
"nym-credential-storage",
|
"nym-credential-storage",
|
||||||
"nym-credentials",
|
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-gateway-requests",
|
"nym-gateway-requests",
|
||||||
"nym-mobile-storage",
|
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-pemstore",
|
"nym-pemstore",
|
||||||
"nym-sphinx",
|
"nym-sphinx",
|
||||||
@@ -3679,14 +3692,6 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nym-mobile-storage"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-multisig-contract-common"
|
name = "nym-multisig-contract-common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -3731,6 +3736,7 @@ dependencies = [
|
|||||||
"nym-client-core",
|
"nym-client-core",
|
||||||
"nym-client-websocket-requests",
|
"nym-client-websocket-requests",
|
||||||
"nym-config",
|
"nym-config",
|
||||||
|
"nym-credential-storage",
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-ordered-buffer",
|
"nym-ordered-buffer",
|
||||||
@@ -3804,6 +3810,7 @@ dependencies = [
|
|||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.2.8",
|
"getrandom 0.2.8",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"sphinx-packet 0.1.0 (git+https://github.com/nymtech/sphinx.git)",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@@ -3819,12 +3826,16 @@ dependencies = [
|
|||||||
name = "nym-sdk"
|
name = "nym-sdk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bip39",
|
||||||
|
"dotenvy",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-bin-common",
|
"nym-bin-common",
|
||||||
"nym-client-core",
|
"nym-client-core",
|
||||||
|
"nym-credential-storage",
|
||||||
|
"nym-credentials",
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-gateway-client",
|
|
||||||
"nym-gateway-requests",
|
"nym-gateway-requests",
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-socks5-client-core",
|
"nym-socks5-client-core",
|
||||||
@@ -3877,10 +3888,10 @@ dependencies = [
|
|||||||
"nym-client-core",
|
"nym-client-core",
|
||||||
"nym-coconut-interface",
|
"nym-coconut-interface",
|
||||||
"nym-config",
|
"nym-config",
|
||||||
|
"nym-credential-storage",
|
||||||
"nym-credentials",
|
"nym-credentials",
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-gateway-requests",
|
"nym-gateway-requests",
|
||||||
"nym-mobile-storage",
|
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-ordered-buffer",
|
"nym-ordered-buffer",
|
||||||
"nym-pemstore",
|
"nym-pemstore",
|
||||||
@@ -3903,10 +3914,10 @@ dependencies = [
|
|||||||
"dirs",
|
"dirs",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
"nym-bandwidth-controller",
|
||||||
"nym-client-core",
|
"nym-client-core",
|
||||||
"nym-config",
|
"nym-config",
|
||||||
"nym-credential-storage",
|
"nym-credential-storage",
|
||||||
"nym-gateway-client",
|
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-service-providers-common",
|
"nym-service-providers-common",
|
||||||
"nym-socks5-proxy-helpers",
|
"nym-socks5-proxy-helpers",
|
||||||
@@ -4046,6 +4057,7 @@ dependencies = [
|
|||||||
name = "nym-sphinx-forwarding"
|
name = "nym-sphinx-forwarding"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"nym-outfox",
|
||||||
"nym-sphinx-addressing",
|
"nym-sphinx-addressing",
|
||||||
"nym-sphinx-params",
|
"nym-sphinx-params",
|
||||||
"nym-sphinx-types",
|
"nym-sphinx-types",
|
||||||
@@ -4076,7 +4088,7 @@ dependencies = [
|
|||||||
name = "nym-sphinx-types"
|
name = "nym-sphinx-types"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sphinx-packet",
|
"sphinx-packet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4190,7 +4202,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-vesting-contract"
|
name = "nym-vesting-contract"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-derive",
|
"cosmwasm-derive",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
@@ -4208,7 +4220,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-vesting-contract-common"
|
name = "nym-vesting-contract-common"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"nym-contracts-common",
|
"nym-contracts-common",
|
||||||
@@ -5877,6 +5889,29 @@ dependencies = [
|
|||||||
"subtle 2.4.1",
|
"subtle 2.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sphinx-packet"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/nymtech/sphinx.git#ca107d94360cdf8bbfbdb12fe5320ed74f80e40c"
|
||||||
|
dependencies = [
|
||||||
|
"aes 0.7.5",
|
||||||
|
"arrayref",
|
||||||
|
"blake2",
|
||||||
|
"bs58",
|
||||||
|
"byteorder",
|
||||||
|
"chacha",
|
||||||
|
"curve25519-dalek",
|
||||||
|
"digest 0.9.0",
|
||||||
|
"hkdf 0.11.0",
|
||||||
|
"hmac 0.11.0",
|
||||||
|
"lioness",
|
||||||
|
"log",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"rand_distr",
|
||||||
|
"sha2 0.9.9",
|
||||||
|
"subtle 2.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
|||||||
+1
-1
@@ -22,6 +22,7 @@ members = [
|
|||||||
"clients/native/websocket-requests",
|
"clients/native/websocket-requests",
|
||||||
"clients/socks5",
|
"clients/socks5",
|
||||||
"common/async-file-watcher",
|
"common/async-file-watcher",
|
||||||
|
"common/bandwidth-controller",
|
||||||
"common/bin-common",
|
"common/bin-common",
|
||||||
"common/client-core",
|
"common/client-core",
|
||||||
"common/client-libs/gateway-client",
|
"common/client-libs/gateway-client",
|
||||||
@@ -38,7 +39,6 @@ members = [
|
|||||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||||
"common/cosmwasm-smart-contracts/service-provider-directory",
|
"common/cosmwasm-smart-contracts/service-provider-directory",
|
||||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||||
"common/mobile-storage",
|
|
||||||
"common/credential-storage",
|
"common/credential-storage",
|
||||||
"common/credentials",
|
"common/credentials",
|
||||||
"common/crypto",
|
"common/crypto",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
|||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym).
|
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/building-nym.html).
|
||||||
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
|
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
|
||||||
|
|
||||||
### Developing
|
### Developing
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@ Critical bug or security issue 💥
|
|||||||
If you're here because you're trying to figure out how to notify us of a security issue, go to Discord, and alert the core engineers:
|
If you're here because you're trying to figure out how to notify us of a security issue, go to Discord, and alert the core engineers:
|
||||||
|
|
||||||
Dave Hrycyszyn futurechimp#5430
|
Dave Hrycyszyn futurechimp#5430
|
||||||
Drazen Urch drazen#4873
|
|
||||||
Jedrzej Stuczynski "Jedrzej | Nym#5666"
|
Jedrzej Stuczynski "Jedrzej | Nym#5666"
|
||||||
|
Fran Arbanas | franarbanas#0995
|
||||||
|
Mark Sinclair | marknym#8088
|
||||||
|
|
||||||
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
|
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
|
||||||
@@ -6,20 +6,16 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bip39 = { workspace = true }
|
|
||||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rand = "0.7.3"
|
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.2"
|
|
||||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||||
|
|
||||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||||
nym-config = { path = "../../common/config" }
|
nym-config = { path = "../../common/config" }
|
||||||
nym-credentials = { path = "../../common/credentials" }
|
nym-credentials = { path = "../../common/credentials" }
|
||||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
|
||||||
nym-bin-common = { path = "../../common/bin-common"}
|
nym-bin-common = { path = "../../common/bin-common"}
|
||||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||||
nym-pemstore = { path = "../../common/pemstore" }
|
nym-pemstore = { path = "../../common/pemstore" }
|
||||||
|
|||||||
@@ -3,24 +3,13 @@
|
|||||||
|
|
||||||
use clap::{ArgGroup, Args, Subcommand};
|
use clap::{ArgGroup, Args, Subcommand};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use nym_bandwidth_controller::acquire::state::State;
|
||||||
use nym_bin_common::completions::ArgShell;
|
use nym_bin_common::completions::ArgShell;
|
||||||
use nym_coconut_interface::{Base58, Parameters};
|
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||||
use nym_credential_storage::storage::Storage;
|
|
||||||
use nym_credential_storage::PersistentStorage;
|
|
||||||
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
|
||||||
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
|
||||||
use nym_crypto::asymmetric::{encryption, identity};
|
|
||||||
use nym_network_defaults::VOUCHER_INFO;
|
|
||||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
use nym_validator_client::nyxd::tx::Hash;
|
|
||||||
use nym_validator_client::CoconutApiClient;
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use crate::client::Client;
|
use crate::error::Result;
|
||||||
use crate::error::{CredentialClientError, Result};
|
|
||||||
use crate::recovery_storage::RecoveryStorage;
|
use crate::recovery_storage::RecoveryStorage;
|
||||||
use crate::state::{KeyPair, State};
|
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
@@ -45,10 +34,6 @@ pub(crate) struct Run {
|
|||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
pub(crate) client_home_directory: std::path::PathBuf,
|
pub(crate) client_home_directory: std::path::PathBuf,
|
||||||
|
|
||||||
/// The nyxd URL that should be used
|
|
||||||
#[clap(long)]
|
|
||||||
pub(crate) nyxd_url: String,
|
|
||||||
|
|
||||||
/// A mnemonic for the account that buys the credential
|
/// A mnemonic for the account that buys the credential
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
pub(crate) mnemonic: String,
|
pub(crate) mnemonic: String,
|
||||||
@@ -67,81 +52,16 @@ pub(crate) struct Run {
|
|||||||
pub(crate) recovery_mode: bool,
|
pub(crate) recovery_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Result<State> {
|
|
||||||
let mut rng = OsRng;
|
|
||||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
|
||||||
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
|
||||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
|
||||||
|
|
||||||
let client = Client::new(nyxd_url, mnemonic);
|
|
||||||
let tx_hash = client
|
|
||||||
.deposit(
|
|
||||||
amount,
|
|
||||||
signing_keypair.public_key.clone(),
|
|
||||||
encryption_keypair.public_key.clone(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let voucher = BandwidthVoucher::new(
|
|
||||||
¶ms,
|
|
||||||
amount.to_string(),
|
|
||||||
VOUCHER_INFO.to_string(),
|
|
||||||
Hash::from_str(&tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
|
|
||||||
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
|
|
||||||
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let state = State { voucher, params };
|
|
||||||
|
|
||||||
Ok(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn get_credential<C: DkgQueryClient + Send + Sync>(
|
|
||||||
state: &State,
|
|
||||||
client: &C,
|
|
||||||
shared_storage: PersistentStorage,
|
|
||||||
) -> Result<()> {
|
|
||||||
let epoch_id = client.get_current_epoch().await?.epoch_id;
|
|
||||||
let threshold = client
|
|
||||||
.get_current_epoch_threshold()
|
|
||||||
.await?
|
|
||||||
.ok_or(CredentialClientError::NoThreshold)?;
|
|
||||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(client, epoch_id).await?;
|
|
||||||
|
|
||||||
let signature = obtain_aggregate_signature(
|
|
||||||
&state.params,
|
|
||||||
&state.voucher,
|
|
||||||
&coconut_api_clients,
|
|
||||||
threshold,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
info!("Signature: {:?}", signature.to_bs58());
|
|
||||||
shared_storage
|
|
||||||
.insert_coconut_credential(
|
|
||||||
state.voucher.get_voucher_value(),
|
|
||||||
VOUCHER_INFO.to_string(),
|
|
||||||
state.voucher.get_private_attributes()[0].to_bs58(),
|
|
||||||
state.voucher.get_private_attributes()[1].to_bs58(),
|
|
||||||
signature.to_bs58(),
|
|
||||||
epoch_id.to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn recover_credentials<C: DkgQueryClient + Send + Sync>(
|
pub(crate) async fn recover_credentials<C: DkgQueryClient + Send + Sync>(
|
||||||
client: &C,
|
client: &C,
|
||||||
recovery_storage: &RecoveryStorage,
|
recovery_storage: &RecoveryStorage,
|
||||||
shared_storage: PersistentStorage,
|
shared_storage: &PersistentStorage,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for voucher in recovery_storage.unconsumed_vouchers()? {
|
for voucher in recovery_storage.unconsumed_vouchers()? {
|
||||||
let state = State {
|
let state = State::new(voucher);
|
||||||
voucher,
|
if let Err(e) =
|
||||||
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
|
nym_bandwidth_controller::acquire::get_credential(&state, client, shared_storage).await
|
||||||
};
|
{
|
||||||
if let Err(e) = get_credential(&state, client, shared_storage.clone()).await {
|
|
||||||
error!(
|
error!(
|
||||||
"Could not recover deposit {} due to {:?}, try again later",
|
"Could not recover deposit {} due to {:?}, try again later",
|
||||||
state.voucher.tx_hash(),
|
state.voucher.tx_hash(),
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use nym_credential_storage::error::StorageError;
|
use nym_credential_storage::error::StorageError;
|
||||||
use nym_credentials::error::Error as CredentialError;
|
use nym_credentials::error::Error as CredentialError;
|
||||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
|
||||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
|
||||||
use nym_validator_client::nyxd::error::NyxdError;
|
use nym_validator_client::nyxd::error::NyxdError;
|
||||||
use nym_validator_client::ValidatorClientError;
|
use nym_validator_client::ValidatorClientError;
|
||||||
|
|
||||||
@@ -18,6 +16,9 @@ pub enum CredentialClientError {
|
|||||||
#[error("IO error: {0}")]
|
#[error("IO error: {0}")]
|
||||||
IOError(#[from] std::io::Error),
|
IOError(#[from] std::io::Error),
|
||||||
|
|
||||||
|
#[error("Bandwidth controller error: {0}")]
|
||||||
|
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
|
||||||
|
|
||||||
#[error("Nyxd error: {0}")]
|
#[error("Nyxd error: {0}")]
|
||||||
Nyxd(#[from] NyxdError),
|
Nyxd(#[from] NyxdError),
|
||||||
|
|
||||||
@@ -27,21 +28,9 @@ pub enum CredentialClientError {
|
|||||||
#[error("Credential error: {0}")]
|
#[error("Credential error: {0}")]
|
||||||
Credential(#[from] CredentialError),
|
Credential(#[from] CredentialError),
|
||||||
|
|
||||||
#[error("The tx hash provided is not valid")]
|
|
||||||
InvalidTxHash,
|
|
||||||
|
|
||||||
#[error("Could not parse Ed25519 data")]
|
|
||||||
Ed25519ParseError(#[from] Ed25519RecoveryError),
|
|
||||||
|
|
||||||
#[error("Could not parse X25519 data")]
|
|
||||||
X25519ParseError(#[from] KeyRecoveryError),
|
|
||||||
|
|
||||||
#[error("Could not use shared storage")]
|
#[error("Could not use shared storage")]
|
||||||
SharedStorageError(#[from] StorageError),
|
SharedStorageError(#[from] StorageError),
|
||||||
|
|
||||||
#[error("Could not get system time")]
|
#[error("Could not get system time")]
|
||||||
SysTimeError(#[from] SystemTimeError),
|
SysTimeError(#[from] SystemTimeError),
|
||||||
|
|
||||||
#[error("Threshold not set yet")]
|
|
||||||
NoThreshold,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
mod client;
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod error;
|
mod error;
|
||||||
mod recovery_storage;
|
mod recovery_storage;
|
||||||
mod state;
|
|
||||||
|
|
||||||
use commands::*;
|
use commands::*;
|
||||||
use error::Result;
|
use error::Result;
|
||||||
@@ -19,7 +17,7 @@ use std::time::{Duration, SystemTime};
|
|||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
use nym_bin_common::logging::setup_logging;
|
use nym_bin_common::logging::setup_logging;
|
||||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
use nym_validator_client::nyxd::CosmWasmClient;
|
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
|
||||||
use nym_validator_client::Config;
|
use nym_validator_client::Config;
|
||||||
|
|
||||||
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
|
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
|
||||||
@@ -35,7 +33,7 @@ struct Cli {
|
|||||||
pub(crate) command: Command,
|
pub(crate) command: Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn block_until_coconut_is_available<C: Clone + CosmWasmClient + Send + Sync>(
|
async fn block_until_coconut_is_available<C: CosmWasmClient + Send + Sync>(
|
||||||
client: &nym_validator_client::Client<C>,
|
client: &nym_validator_client::Client<C>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
@@ -77,21 +75,34 @@ async fn main() -> Result<()> {
|
|||||||
.client_home_directory
|
.client_home_directory
|
||||||
.join(DATA_DIR)
|
.join(DATA_DIR)
|
||||||
.join(CRED_DB_FILE_NAME);
|
.join(CRED_DB_FILE_NAME);
|
||||||
let shared_storage = nym_credential_storage::initialise_storage(db_path).await;
|
let shared_storage =
|
||||||
|
nym_credential_storage::initialise_persistent_storage(db_path).await;
|
||||||
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
|
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
|
||||||
|
|
||||||
let network_details = NymNetworkDetails::new_from_env();
|
let network_details = NymNetworkDetails::new_from_env();
|
||||||
let config = Config::try_from_nym_network_details(&network_details)?;
|
let config = Config::try_from_nym_network_details(&network_details).expect(
|
||||||
let client = nym_validator_client::Client::new_query(config)?;
|
"failed to construct valid validator client config with the provided network",
|
||||||
|
);
|
||||||
|
let amount = Coin::new(
|
||||||
|
r.amount as u128,
|
||||||
|
network_details.chain_details.mix_denom.base,
|
||||||
|
);
|
||||||
|
let client =
|
||||||
|
nym_validator_client::Client::new_signing(config, r.mnemonic.parse().unwrap())?;
|
||||||
|
|
||||||
block_until_coconut_is_available(&client).await?;
|
block_until_coconut_is_available(&client).await?;
|
||||||
info!("Starting depositing funds, don't kill the process");
|
info!("Starting depositing funds, don't kill the process");
|
||||||
|
|
||||||
if !r.recovery_mode {
|
if !r.recovery_mode {
|
||||||
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
|
let state =
|
||||||
if get_credential(&state, &client.nyxd, shared_storage)
|
nym_bandwidth_controller::acquire::deposit(&client.nyxd, amount).await?;
|
||||||
.await
|
if nym_bandwidth_controller::acquire::get_credential(
|
||||||
.is_err()
|
&state,
|
||||||
|
&client,
|
||||||
|
&shared_storage,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
{
|
{
|
||||||
warn!("Failed to obtain credential. Dumping recovery data.",);
|
warn!("Failed to obtain credential. Dumping recovery data.",);
|
||||||
match recovery_storage.insert_voucher(&state.voucher) {
|
match recovery_storage.insert_voucher(&state.voucher) {
|
||||||
@@ -104,11 +115,11 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
recover_credentials(&client.nyxd, &recovery_storage, shared_storage).await?;
|
recover_credentials(&client.nyxd, &recovery_storage, &shared_storage).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name),
|
Command::Completions(c) => c.generate(&mut Cli::command(), bin_name),
|
||||||
Command::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
|
Command::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
|||||||
tokio-tungstenite = "0.14" # websocket
|
tokio-tungstenite = "0.14" # websocket
|
||||||
|
|
||||||
## internal
|
## internal
|
||||||
|
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
||||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
|
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
|
||||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
@@ -41,7 +42,6 @@ nym-config = { path = "../../common/config" }
|
|||||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
nym-credentials = { path = "../../common/credentials" }
|
nym-credentials = { path = "../../common/credentials" }
|
||||||
nym-crypto = { path = "../../common/crypto" }
|
nym-crypto = { path = "../../common/crypto" }
|
||||||
nym-gateway-client = { path = "../../common/client-libs/gateway-client" }
|
|
||||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::error::ClientError;
|
|||||||
use crate::websocket;
|
use crate::websocket;
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
use nym_client_core::client::base_client::{
|
use nym_client_core::client::base_client::{
|
||||||
non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||||
};
|
};
|
||||||
@@ -14,7 +15,6 @@ use nym_client_core::client::received_buffer::{
|
|||||||
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
|
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
|
||||||
};
|
};
|
||||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use nym_gateway_client::bandwidth::BandwidthController;
|
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
use nym_task::TaskManager;
|
use nym_task::TaskManager;
|
||||||
@@ -23,6 +23,7 @@ use std::error::Error;
|
|||||||
use tokio::sync::watch::error::SendError;
|
use tokio::sync::watch::error::SendError;
|
||||||
|
|
||||||
pub use nym_client_core::client::key_manager::KeyManager;
|
pub use nym_client_core::client::key_manager::KeyManager;
|
||||||
|
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||||
pub use nym_sphinx::addressing::clients::Recipient;
|
pub use nym_sphinx::addressing::clients::Recipient;
|
||||||
pub use nym_sphinx::receiver::ReconstructedMessage;
|
pub use nym_sphinx::receiver::ReconstructedMessage;
|
||||||
use nym_validator_client::Client;
|
use nym_validator_client::Client;
|
||||||
@@ -58,7 +59,7 @@ impl SocketClient {
|
|||||||
|
|
||||||
async fn create_bandwidth_controller(
|
async fn create_bandwidth_controller(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> BandwidthController<Client<QueryNyxdClient>> {
|
) -> BandwidthController<Client<QueryNyxdClient>, PersistentStorage> {
|
||||||
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
||||||
let mut client_config =
|
let mut client_config =
|
||||||
nym_validator_client::Config::try_from_nym_network_details(&details)
|
nym_validator_client::Config::try_from_nym_network_details(&details)
|
||||||
@@ -78,7 +79,10 @@ impl SocketClient {
|
|||||||
let client = nym_validator_client::Client::new_query(client_config)
|
let client = nym_validator_client::Client::new_query(client_config)
|
||||||
.expect("Could not construct query client");
|
.expect("Could not construct query client");
|
||||||
BandwidthController::new(
|
BandwidthController::new(
|
||||||
nym_credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
nym_credential_storage::initialise_persistent_storage(
|
||||||
|
config.get_base().get_database_path(),
|
||||||
|
)
|
||||||
|
.await,
|
||||||
client,
|
client,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::{
|
|||||||
use clap::Args;
|
use clap::Args;
|
||||||
use nym_bin_common::output_format::OutputFormat;
|
use nym_bin_common::output_format::OutputFormat;
|
||||||
use nym_config::NymConfig;
|
use nym_config::NymConfig;
|
||||||
|
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||||
use nym_crypto::asymmetric::identity;
|
use nym_crypto::asymmetric::identity;
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@@ -114,7 +115,7 @@ impl Display for InitResults {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "{}", self.client_core)?;
|
writeln!(f, "{}", self.client_core)?;
|
||||||
writeln!(f, "Client listening port: {}", self.client_listening_port)?;
|
writeln!(f, "Client listening port: {}", self.client_listening_port)?;
|
||||||
write!(f, "address of this client: {}", self.client_address)
|
write!(f, "Address of this client: {}", self.client_address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +152,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
|||||||
|
|
||||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||||
// one but with keys kept, or reusing the gateway configuration.
|
// one but with keys kept, or reusing the gateway configuration.
|
||||||
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _>(
|
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, PersistentStorage>(
|
||||||
register_gateway,
|
register_gateway,
|
||||||
user_chosen_gateway_id,
|
user_chosen_gateway_id,
|
||||||
config.get_base(),
|
config.get_base(),
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ nym-bin-common = { path = "../../common/bin-common", features = ["output_format"
|
|||||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
|
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
|
||||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
nym-config = { path = "../../common/config" }
|
nym-config = { path = "../../common/config" }
|
||||||
nym-mobile-storage = { path = "../../common/mobile-storage", optional = true }
|
|
||||||
nym-credentials = { path = "../../common/credentials" }
|
nym-credentials = { path = "../../common/credentials" }
|
||||||
nym-crypto = { path = "../../common/crypto" }
|
nym-crypto = { path = "../../common/crypto" }
|
||||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||||
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
use clap::Args;
|
use clap::Args;
|
||||||
use nym_bin_common::output_format::OutputFormat;
|
use nym_bin_common::output_format::OutputFormat;
|
||||||
use nym_config::NymConfig;
|
use nym_config::NymConfig;
|
||||||
|
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||||
use nym_crypto::asymmetric::identity;
|
use nym_crypto::asymmetric::identity;
|
||||||
use nym_socks5_client_core::config::Config;
|
use nym_socks5_client_core::config::Config;
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
@@ -115,8 +116,8 @@ impl InitResults {
|
|||||||
impl Display for InitResults {
|
impl Display for InitResults {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "{}", self.client_core)?;
|
writeln!(f, "{}", self.client_core)?;
|
||||||
write!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)?;
|
writeln!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)?;
|
||||||
write!(f, "address of this client: {}", self.client_address)
|
write!(f, "Address of this client: {}", self.client_address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
|||||||
|
|
||||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||||
// one but with keys kept, or reusing the gateway configuration.
|
// one but with keys kept, or reusing the gateway configuration.
|
||||||
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _>(
|
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, PersistentStorage>(
|
||||||
register_gateway,
|
register_gateway,
|
||||||
user_chosen_gateway_id,
|
user_chosen_gateway_id,
|
||||||
config.get_base(),
|
config.get_base(),
|
||||||
@@ -180,7 +181,6 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
|||||||
let init_results = InitResults::new(&config, &address);
|
let init_results = InitResults::new(&config, &address);
|
||||||
println!("{}", args.output.format(&init_results));
|
println!("{}", args.output.format(&init_results));
|
||||||
|
|
||||||
eprintln!("\nThe address of this client is: {}\n", address);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,12 @@ wasm-bindgen-futures = "0.4"
|
|||||||
|
|
||||||
# internal
|
# internal
|
||||||
nym-client-core = { path = "../../common/client-core", default-features = false, features = ["wasm"] }
|
nym-client-core = { path = "../../common/client-core", default-features = false, features = ["wasm"] }
|
||||||
|
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
nym-credentials = { path = "../../common/credentials" }
|
nym-credentials = { path = "../../common/credentials" }
|
||||||
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
nym-crypto = { path = "../../common/crypto" }
|
nym-crypto = { path = "../../common/crypto" }
|
||||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||||
nym-gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
|
|
||||||
nym-validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
nym-validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||||
wasm-utils = { path = "../../common/wasm-utils" }
|
wasm-utils = { path = "../../common/wasm-utils" }
|
||||||
nym-task = { path = "../../common/task" }
|
nym-task = { path = "../../common/task" }
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ use self::config::Config;
|
|||||||
use crate::client::helpers::InputSender;
|
use crate::client::helpers::InputSender;
|
||||||
use crate::client::response_pusher::ResponsePusher;
|
use crate::client::response_pusher::ResponsePusher;
|
||||||
use js_sys::Promise;
|
use js_sys::Promise;
|
||||||
|
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
||||||
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
use nym_client_core::client::base_client::{
|
use nym_client_core::client::base_client::{
|
||||||
BaseClientBuilder, ClientInput, ClientOutput, CredentialsToggle,
|
BaseClientBuilder, ClientInput, ClientOutput, CredentialsToggle,
|
||||||
};
|
};
|
||||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||||
use nym_client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
|
use nym_client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
|
||||||
use nym_gateway_client::bandwidth::BandwidthController;
|
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||||
use nym_gateway_client::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
@@ -48,7 +49,8 @@ pub struct NymClientBuilder {
|
|||||||
on_message: js_sys::Function,
|
on_message: js_sys::Function,
|
||||||
|
|
||||||
// unimplemented:
|
// unimplemented:
|
||||||
bandwidth_controller: Option<BandwidthController<FakeClient<DirectSigningNyxdClient>>>,
|
bandwidth_controller:
|
||||||
|
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
||||||
disabled_credentials: bool,
|
disabled_credentials: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "nym-bandwidth-controller"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bip39 = { workspace = true }
|
||||||
|
rand = "0.7.3"
|
||||||
|
thiserror = "1.0"
|
||||||
|
url = "2.2"
|
||||||
|
|
||||||
|
nym-coconut-interface = { path = "../coconut-interface" }
|
||||||
|
nym-credential-storage = { path = "../credential-storage" }
|
||||||
|
nym-credentials = { path = "../credentials" }
|
||||||
|
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||||
|
nym-network-defaults = { path = "../network-defaults" }
|
||||||
|
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||||
|
|
||||||
|
|
||||||
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
|
||||||
|
path = "../client-libs/validator-client"
|
||||||
|
features = ["nyxd-client"]
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::error::BandwidthControllerError;
|
||||||
|
use nym_coconut_interface::{Base58, Parameters};
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
|
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||||
|
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||||
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
|
use nym_network_defaults::VOUCHER_INFO;
|
||||||
|
use nym_validator_client::nyxd::traits::CoconutBandwidthSigningClient;
|
||||||
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
|
use nym_validator_client::nyxd::tx::Hash;
|
||||||
|
use nym_validator_client::nyxd::Coin;
|
||||||
|
use nym_validator_client::CoconutApiClient;
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use state::{KeyPair, State};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub mod state;
|
||||||
|
|
||||||
|
pub async fn deposit<C>(client: &C, amount: Coin) -> Result<State, BandwidthControllerError>
|
||||||
|
where
|
||||||
|
C: CoconutBandwidthSigningClient,
|
||||||
|
{
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||||
|
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
||||||
|
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||||
|
let voucher_value = amount.amount.to_string();
|
||||||
|
|
||||||
|
let tx_hash = client
|
||||||
|
.deposit(
|
||||||
|
amount,
|
||||||
|
String::from(VOUCHER_INFO),
|
||||||
|
signing_keypair.public_key.clone(),
|
||||||
|
encryption_keypair.public_key.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.transaction_hash
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let voucher = BandwidthVoucher::new(
|
||||||
|
¶ms,
|
||||||
|
voucher_value,
|
||||||
|
VOUCHER_INFO.to_string(),
|
||||||
|
Hash::from_str(&tx_hash).map_err(|_| BandwidthControllerError::InvalidTxHash)?,
|
||||||
|
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
|
||||||
|
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let state = State { voucher, params };
|
||||||
|
|
||||||
|
Ok(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_credential<C: DkgQueryClient + Send + Sync, St: Storage>(
|
||||||
|
state: &State,
|
||||||
|
client: &C,
|
||||||
|
storage: &St,
|
||||||
|
) -> Result<(), BandwidthControllerError> {
|
||||||
|
let epoch_id = client.get_current_epoch().await?.epoch_id;
|
||||||
|
let threshold = client
|
||||||
|
.get_current_epoch_threshold()
|
||||||
|
.await?
|
||||||
|
.ok_or(BandwidthControllerError::NoThreshold)?;
|
||||||
|
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(client, epoch_id).await?;
|
||||||
|
|
||||||
|
let signature = obtain_aggregate_signature(
|
||||||
|
&state.params,
|
||||||
|
&state.voucher,
|
||||||
|
&coconut_api_clients,
|
||||||
|
threshold,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
storage
|
||||||
|
.insert_coconut_credential(
|
||||||
|
state.voucher.get_voucher_value(),
|
||||||
|
VOUCHER_INFO.to_string(),
|
||||||
|
state.voucher.get_private_attributes()[0].to_bs58(),
|
||||||
|
state.voucher.get_private_attributes()[1].to_bs58(),
|
||||||
|
signature.to_bs58(),
|
||||||
|
epoch_id.to_string(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use nym_coconut_interface::Parameters;
|
use nym_coconut_interface::Parameters;
|
||||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||||
|
|
||||||
use nym_crypto::asymmetric::{encryption, identity};
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
|
|
||||||
@@ -29,7 +29,16 @@ impl From<encryption::KeyPair> for KeyPair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct State {
|
pub struct State {
|
||||||
pub voucher: BandwidthVoucher,
|
pub voucher: BandwidthVoucher,
|
||||||
pub params: Parameters,
|
pub params: Parameters,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn new(voucher: BandwidthVoucher) -> Self {
|
||||||
|
State {
|
||||||
|
voucher,
|
||||||
|
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use nym_coconut_interface::CoconutError;
|
||||||
|
use nym_credential_storage::error::StorageError;
|
||||||
|
use nym_credentials::error::Error as CredentialsError;
|
||||||
|
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||||
|
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||||
|
use nym_validator_client::error::ValidatorClientError;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum BandwidthControllerError {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
#[error("Nyxd error: {0}")]
|
||||||
|
Nyxd(#[from] nym_validator_client::nyxd::error::NyxdError),
|
||||||
|
|
||||||
|
#[error("There was a credential storage error - {0}")]
|
||||||
|
CredentialStorageError(#[from] StorageError),
|
||||||
|
|
||||||
|
#[error("Coconut error - {0}")]
|
||||||
|
CoconutError(#[from] CoconutError),
|
||||||
|
|
||||||
|
#[error("Validator client error - {0}")]
|
||||||
|
ValidatorError(#[from] ValidatorClientError),
|
||||||
|
|
||||||
|
#[error("Credential error - {0}")]
|
||||||
|
CredentialError(#[from] CredentialsError),
|
||||||
|
|
||||||
|
#[error("Could not parse Ed25519 data")]
|
||||||
|
Ed25519ParseError(#[from] Ed25519RecoveryError),
|
||||||
|
|
||||||
|
#[error("Could not parse X25519 data")]
|
||||||
|
X25519ParseError(#[from] KeyRecoveryError),
|
||||||
|
|
||||||
|
#[error("The tx hash provided is not valid")]
|
||||||
|
InvalidTxHash,
|
||||||
|
|
||||||
|
#[error("Threshold not set yet")]
|
||||||
|
NoThreshold,
|
||||||
|
}
|
||||||
+16
-41
@@ -1,28 +1,10 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::GatewayClientError;
|
use crate::error::BandwidthControllerError;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use crate::wasm_mockups::Storage;
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
use nym_credential_storage::storage::Storage;
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use mobile_storage::Storage;
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use mobile_storage::StorageError;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use crate::wasm_mockups::StorageError;
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
use nym_credential_storage::error::StorageError;
|
use nym_credential_storage::error::StorageError;
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use {
|
use {
|
||||||
@@ -35,38 +17,32 @@ use {
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
|
|
||||||
// TODO: make it nicer for wasm (I don't want to touch it for this experiment)
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use crate::wasm_mockups::PersistentStorage;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use crate::wasm_mockups::DkgQueryClient;
|
use crate::wasm_mockups::DkgQueryClient;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[cfg(not(target_os = "android"))]
|
pub mod acquire;
|
||||||
use nym_credential_storage::PersistentStorage;
|
pub mod error;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub mod wasm_mockups;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
pub struct BandwidthController<C, St: Storage> {
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use mobile_storage::PersistentStorage;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct BandwidthController<C, St: Storage = PersistentStorage> {
|
|
||||||
storage: St,
|
storage: St,
|
||||||
client: C,
|
client: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, St> BandwidthController<C, St>
|
impl<C, St: Storage> BandwidthController<C, St> {
|
||||||
where
|
|
||||||
St: Storage + 'static,
|
|
||||||
{
|
|
||||||
pub fn new(storage: St, client: C) -> Self {
|
pub fn new(storage: St, client: C) -> Self {
|
||||||
BandwidthController { storage, client }
|
BandwidthController { storage, client }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn storage(&self) -> &St {
|
||||||
|
&self.storage
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn prepare_coconut_credential(
|
pub async fn prepare_coconut_credential(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<(nym_coconut_interface::Credential, i64), GatewayClientError>
|
) -> Result<(nym_coconut_interface::Credential, i64), BandwidthControllerError>
|
||||||
where
|
where
|
||||||
C: DkgQueryClient + Sync + Send,
|
C: DkgQueryClient + Sync + Send,
|
||||||
{
|
{
|
||||||
@@ -86,8 +62,7 @@ where
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let coconut_api_clients =
|
let coconut_api_clients =
|
||||||
nym_validator_client::CoconutApiClient::all_coconut_api_clients(&self.client, epoch_id)
|
nym_validator_client::CoconutApiClient::all_coconut_api_clients(&self.client, epoch_id)
|
||||||
.await
|
.await?;
|
||||||
.expect("Could not query api clients");
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
let coconut_api_clients = vec![];
|
let coconut_api_clients = vec![];
|
||||||
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?;
|
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?;
|
||||||
@@ -107,7 +82,7 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn consume_credential(&self, id: i64) -> Result<(), GatewayClientError> {
|
pub async fn consume_credential(&self, id: i64) -> Result<(), BandwidthControllerError> {
|
||||||
// JS: shouldn't we send some contract/validator/gateway message here to actually, you know,
|
// JS: shouldn't we send some contract/validator/gateway message here to actually, you know,
|
||||||
// consume it?
|
// consume it?
|
||||||
Ok(self.storage.consume_coconut_credential(id).await?)
|
Ok(self.storage.consume_coconut_credential(id).await?)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub struct DirectSigningNyxdClient {}
|
||||||
|
|
||||||
|
pub trait DkgQueryClient {}
|
||||||
|
|
||||||
|
// impl CosmWasmClient for DirectSigningNyxdClient {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Client<C> {
|
||||||
|
_phantom: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> DkgQueryClient for Client<C> {}
|
||||||
@@ -25,6 +25,7 @@ tokio = { version = "1.24.1", features = ["macros"]}
|
|||||||
time = "0.3.17"
|
time = "0.3.17"
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
|
nym-bandwidth-controller = { path = "../bandwidth-controller" }
|
||||||
nym-config = { path = "../config" }
|
nym-config = { path = "../config" }
|
||||||
nym-crypto = { path = "../crypto" }
|
nym-crypto = { path = "../crypto" }
|
||||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||||
@@ -36,6 +37,7 @@ nym-pemstore = { path = "../pemstore" }
|
|||||||
nym-topology = { path = "../topology" }
|
nym-topology = { path = "../topology" }
|
||||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||||
nym-task = { path = "../task" }
|
nym-task = { path = "../task" }
|
||||||
|
nym-credential-storage = { path = "../credential-storage" }
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
|
||||||
path = "../client-libs/validator-client"
|
path = "../client-libs/validator-client"
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ use crate::error::ClientCoreError;
|
|||||||
use crate::spawn_future;
|
use crate::spawn_future;
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
use nym_crypto::asymmetric::{encryption, identity};
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
use nym_gateway_client::bandwidth::BandwidthController;
|
|
||||||
use nym_gateway_client::{
|
use nym_gateway_client::{
|
||||||
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
||||||
MixnetMessageSender,
|
MixnetMessageSender,
|
||||||
@@ -43,11 +43,12 @@ use std::time::Duration;
|
|||||||
use tap::TapFallible;
|
use tap::TapFallible;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use nym_gateway_client::wasm_mockups::DkgQueryClient;
|
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||||
pub mod non_wasm_helpers;
|
pub mod non_wasm_helpers;
|
||||||
@@ -151,7 +152,7 @@ impl From<bool> for CredentialsToggle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BaseClientBuilder<'a, B, C> {
|
pub struct BaseClientBuilder<'a, B, C, St: Storage> {
|
||||||
// due to wasm limitations I had to split it like this : (
|
// due to wasm limitations I had to split it like this : (
|
||||||
gateway_config: &'a GatewayEndpointConfig,
|
gateway_config: &'a GatewayEndpointConfig,
|
||||||
debug_config: &'a DebugConfig,
|
debug_config: &'a DebugConfig,
|
||||||
@@ -160,21 +161,22 @@ pub struct BaseClientBuilder<'a, B, C> {
|
|||||||
reply_storage_backend: B,
|
reply_storage_backend: B,
|
||||||
|
|
||||||
custom_topology_provider: Option<Box<dyn TopologyProvider>>,
|
custom_topology_provider: Option<Box<dyn TopologyProvider>>,
|
||||||
bandwidth_controller: Option<BandwidthController<C>>,
|
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||||
key_manager: KeyManager,
|
key_manager: KeyManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, B, C> BaseClientBuilder<'a, B, C>
|
impl<'a, B, C, St> BaseClientBuilder<'a, B, C, St>
|
||||||
where
|
where
|
||||||
B: ReplyStorageBackend + Send + Sync + 'static,
|
B: ReplyStorageBackend + Send + Sync + 'static,
|
||||||
C: DkgQueryClient + Sync + Send + 'static,
|
C: DkgQueryClient + Sync + Send + 'static,
|
||||||
|
St: Storage + 'static,
|
||||||
{
|
{
|
||||||
pub fn new_from_base_config<T>(
|
pub fn new_from_base_config<T>(
|
||||||
base_config: &'a Config<T>,
|
base_config: &'a Config<T>,
|
||||||
key_manager: KeyManager,
|
key_manager: KeyManager,
|
||||||
bandwidth_controller: Option<BandwidthController<C>>,
|
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||||
reply_storage_backend: B,
|
reply_storage_backend: B,
|
||||||
) -> BaseClientBuilder<'a, B, C> {
|
) -> BaseClientBuilder<'a, B, C, St> {
|
||||||
BaseClientBuilder {
|
BaseClientBuilder {
|
||||||
gateway_config: base_config.get_gateway_endpoint_config(),
|
gateway_config: base_config.get_gateway_endpoint_config(),
|
||||||
debug_config: base_config.get_debug_config(),
|
debug_config: base_config.get_debug_config(),
|
||||||
@@ -191,11 +193,11 @@ where
|
|||||||
gateway_config: &'a GatewayEndpointConfig,
|
gateway_config: &'a GatewayEndpointConfig,
|
||||||
debug_config: &'a DebugConfig,
|
debug_config: &'a DebugConfig,
|
||||||
key_manager: KeyManager,
|
key_manager: KeyManager,
|
||||||
bandwidth_controller: Option<BandwidthController<C>>,
|
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||||
reply_storage_backend: B,
|
reply_storage_backend: B,
|
||||||
credentials_toggle: CredentialsToggle,
|
credentials_toggle: CredentialsToggle,
|
||||||
nym_api_endpoints: Vec<Url>,
|
nym_api_endpoints: Vec<Url>,
|
||||||
) -> BaseClientBuilder<'a, B, C> {
|
) -> BaseClientBuilder<'a, B, C, St> {
|
||||||
BaseClientBuilder {
|
BaseClientBuilder {
|
||||||
gateway_config,
|
gateway_config,
|
||||||
debug_config,
|
debug_config,
|
||||||
@@ -306,7 +308,7 @@ where
|
|||||||
mixnet_message_sender: MixnetMessageSender,
|
mixnet_message_sender: MixnetMessageSender,
|
||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
) -> Result<GatewayClient<C>, ClientCoreError> {
|
) -> Result<GatewayClient<C, St>, ClientCoreError> {
|
||||||
let gateway_id = self.gateway_config.gateway_id.clone();
|
let gateway_id = self.gateway_config.gateway_id.clone();
|
||||||
if gateway_id.is_empty() {
|
if gateway_id.is_empty() {
|
||||||
return Err(ClientCoreError::GatewayIdUnknown);
|
return Err(ClientCoreError::GatewayIdUnknown);
|
||||||
@@ -403,7 +405,7 @@ where
|
|||||||
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
||||||
// requests?
|
// requests?
|
||||||
fn start_mix_traffic_controller(
|
fn start_mix_traffic_controller(
|
||||||
gateway_client: GatewayClient<C>,
|
gateway_client: GatewayClient<C, St>,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
) -> BatchMixMessageSender {
|
) -> BatchMixMessageSender {
|
||||||
info!("Starting mix traffic controller...");
|
info!("Starting mix traffic controller...");
|
||||||
|
|||||||
@@ -203,10 +203,6 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
// This isn't a problem, if the channel is full means we're already sending the
|
// This isn't a problem, if the channel is full means we're already sending the
|
||||||
// max amount of messages downstream can handle.
|
// max amount of messages downstream can handle.
|
||||||
log::debug!("Failed to send cover message - channel full");
|
log::debug!("Failed to send cover message - channel full");
|
||||||
// However it's still useful to alert the user that the gateway or the link to
|
|
||||||
// the gateway can't keep up. Either due to insufficient bandwidth on the
|
|
||||||
// client side, or that the gateway is overloaded.
|
|
||||||
log::warn!("Failed to send sphinx packet - gateway or connection to gateway can't keep up");
|
|
||||||
}
|
}
|
||||||
TrySendError::Closed(_) => {
|
TrySendError::Closed(_) => {
|
||||||
log::warn!("Failed to send cover message - channel closed");
|
log::warn!("Failed to send cover message - channel closed");
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ use log::*;
|
|||||||
use nym_gateway_client::GatewayClient;
|
use nym_gateway_client::GatewayClient;
|
||||||
use nym_sphinx::forwarding::packet::MixPacket;
|
use nym_sphinx::forwarding::packet::MixPacket;
|
||||||
|
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use nym_gateway_client::wasm_mockups::DkgQueryClient;
|
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||||
|
|
||||||
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
||||||
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
||||||
@@ -19,10 +20,10 @@ pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
|||||||
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
|
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
|
||||||
const MAX_FAILURE_COUNT: usize = 100;
|
const MAX_FAILURE_COUNT: usize = 100;
|
||||||
|
|
||||||
pub struct MixTrafficController<C> {
|
pub struct MixTrafficController<C, St: Storage> {
|
||||||
// TODO: most likely to be replaced by some higher level construct as
|
// TODO: most likely to be replaced by some higher level construct as
|
||||||
// later on gateway_client will need to be accessible by other entities
|
// later on gateway_client will need to be accessible by other entities
|
||||||
gateway_client: GatewayClient<C>,
|
gateway_client: GatewayClient<C, St>,
|
||||||
mix_rx: BatchMixMessageReceiver,
|
mix_rx: BatchMixMessageReceiver,
|
||||||
|
|
||||||
// TODO: this is temporary work-around.
|
// TODO: this is temporary work-around.
|
||||||
@@ -30,13 +31,14 @@ pub struct MixTrafficController<C> {
|
|||||||
consecutive_gateway_failure_count: usize,
|
consecutive_gateway_failure_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> MixTrafficController<C>
|
impl<C, St> MixTrafficController<C, St>
|
||||||
where
|
where
|
||||||
C: DkgQueryClient + Sync + Send + 'static,
|
C: DkgQueryClient + Sync + Send + 'static,
|
||||||
|
St: Storage + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
gateway_client: GatewayClient<C>,
|
gateway_client: GatewayClient<C, St>,
|
||||||
) -> (MixTrafficController<C>, BatchMixMessageSender) {
|
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
|
||||||
let (sphinx_message_sender, sphinx_message_receiver) =
|
let (sphinx_message_sender, sphinx_message_receiver) =
|
||||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -302,24 +302,34 @@ where
|
|||||||
self.sending_delay_controller.current_multiplier()
|
self.sending_delay_controller.current_multiplier()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Even just a single used slot is enough to signal backpressure
|
if self
|
||||||
if used_slots > 0 {
|
.sending_delay_controller
|
||||||
|
.is_backpressure_currently_detected(used_slots)
|
||||||
|
{
|
||||||
log::trace!("Backpressure detected");
|
log::trace!("Backpressure detected");
|
||||||
self.sending_delay_controller.record_backpressure_detected();
|
self.sending_delay_controller.record_backpressure_detected();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the buffer is running out, slow down the sending rate
|
// If the buffer is running out, slow down the sending rate by increasing the delay
|
||||||
|
// multiplier.
|
||||||
if self.mix_tx.capacity() == 0
|
if self.mix_tx.capacity() == 0
|
||||||
&& self.sending_delay_controller.not_increased_delay_recently()
|
&& self.sending_delay_controller.not_increased_delay_recently()
|
||||||
{
|
{
|
||||||
self.sending_delay_controller.increase_delay_multiplier();
|
self.sending_delay_controller.increase_delay_multiplier();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Very carefully step up the sending rate in case it seems like we can solidly handle the
|
// If it looks like we are sending reliably, increase the sending rate by decreasing the
|
||||||
// current rate.
|
// sending delay multiplier.
|
||||||
if self.sending_delay_controller.is_sending_reliable() {
|
if !self
|
||||||
|
.sending_delay_controller
|
||||||
|
.was_backpressure_detected_recently()
|
||||||
|
&& self.sending_delay_controller.not_decreased_delay_recently()
|
||||||
|
{
|
||||||
self.sending_delay_controller.decrease_delay_multiplier();
|
self.sending_delay_controller.decrease_delay_multiplier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of multiplier changes, and log if necessary.
|
||||||
|
self.sending_delay_controller.record_delay_multiplier();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_next_message(&mut self) -> Option<RealMessage> {
|
fn pop_next_message(&mut self) -> Option<RealMessage> {
|
||||||
@@ -498,23 +508,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
fn log_status_infrequent(&self) {
|
|
||||||
if self.sending_delay_controller.current_multiplier() > 1 {
|
|
||||||
log::warn!(
|
|
||||||
"Unable to send packets at the default rate - rate reduced by setting the delay multiplier set to: {}",
|
|
||||||
self.sending_delay_controller.current_multiplier()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||||
debug!("Started OutQueueControl with graceful shutdown support");
|
debug!("Started OutQueueControl with graceful shutdown support");
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let mut status_timer = tokio::time::interval(Duration::from_secs(5));
|
let mut status_timer = tokio::time::interval(Duration::from_secs(5));
|
||||||
let mut infrequent_status_timer = tokio::time::interval(Duration::from_secs(60));
|
|
||||||
|
|
||||||
while !shutdown.is_shutdown() {
|
while !shutdown.is_shutdown() {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
@@ -525,9 +524,6 @@ where
|
|||||||
_ = status_timer.tick() => {
|
_ = status_timer.tick() => {
|
||||||
self.log_status(&mut shutdown);
|
self.log_status(&mut shutdown);
|
||||||
}
|
}
|
||||||
_ = infrequent_status_timer.tick() => {
|
|
||||||
self.log_status_infrequent();
|
|
||||||
}
|
|
||||||
next_message = self.next() => if let Some(next_message) = next_message {
|
next_message = self.next() => if let Some(next_message) = next_message {
|
||||||
self.on_message(next_message).await;
|
self.on_message(next_message).await;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+68
-16
@@ -11,15 +11,20 @@ const INCREASE_DELAY_MIN_CHANGE_INTERVAL_SECS: u64 = 1;
|
|||||||
// The minimum time between decreasing the average delay between packets. We don't want to change
|
// The minimum time between decreasing the average delay between packets. We don't want to change
|
||||||
// to quickly to keep things somewhat stable. Also there are buffers downstreams meaning we need to
|
// to quickly to keep things somewhat stable. Also there are buffers downstreams meaning we need to
|
||||||
// wait a little to see the effect before we decrease further.
|
// wait a little to see the effect before we decrease further.
|
||||||
const DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS: u64 = 30;
|
const DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS: u64 = 2;
|
||||||
|
// The queue length that is required for us to register that backpressure occured. If there are
|
||||||
|
// more than this many packets waiting to be sent, we consider the channel to be under
|
||||||
|
// backpressure.
|
||||||
|
const BACKPRESSURE_THRESHOLD: usize = 10;
|
||||||
// If we enough time passes without any sign of backpressure in the channel, we can consider
|
// If we enough time passes without any sign of backpressure in the channel, we can consider
|
||||||
// lowering the average delay. The goal is to keep somewhat stable, rather than maxing out
|
// lowering the average delay.
|
||||||
// bandwidth at all times.
|
const ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS: u64 = 2;
|
||||||
const ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS: u64 = 30;
|
|
||||||
// The maximum multiplier we apply to the base average Poisson delay.
|
// The maximum multiplier we apply to the base average Poisson delay.
|
||||||
const MAX_DELAY_MULTIPLIER: u32 = 6;
|
const MAX_DELAY_MULTIPLIER: u32 = 6;
|
||||||
// The minium multiplier we apply to the base average Poisson delay.
|
// The minium multiplier we apply to the base average Poisson delay.
|
||||||
const MIN_DELAY_MULTIPLIER: u32 = 1;
|
const MIN_DELAY_MULTIPLIER: u32 = 1;
|
||||||
|
// If the multipler increases we log it, but we don't want to log about it too often.
|
||||||
|
const INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS: u64 = 60;
|
||||||
|
|
||||||
pub(crate) struct SendingDelayController {
|
pub(crate) struct SendingDelayController {
|
||||||
/// Multiply the average sending delay.
|
/// Multiply the average sending delay.
|
||||||
@@ -33,6 +38,14 @@ pub(crate) struct SendingDelayController {
|
|||||||
/// Minimum delay multiplier
|
/// Minimum delay multiplier
|
||||||
lower_bound: u32,
|
lower_bound: u32,
|
||||||
|
|
||||||
|
/// We counter the number of times the multiplier has been elevated. If it is elevated for long
|
||||||
|
/// enough we need to log about it.
|
||||||
|
multiplier_elevated_counter: u32,
|
||||||
|
|
||||||
|
/// We can't log about the elevated multiplier too often, so we keep track of the last time we
|
||||||
|
/// did,
|
||||||
|
time_when_logged_about_elevated_multiplier: Instant,
|
||||||
|
|
||||||
/// To make sure we don't change the multiplier to fast, we limit a change to some duration
|
/// To make sure we don't change the multiplier to fast, we limit a change to some duration
|
||||||
time_when_changed: Instant,
|
time_when_changed: Instant,
|
||||||
|
|
||||||
@@ -55,6 +68,9 @@ impl SendingDelayController {
|
|||||||
current_multiplier: MIN_DELAY_MULTIPLIER,
|
current_multiplier: MIN_DELAY_MULTIPLIER,
|
||||||
upper_bound,
|
upper_bound,
|
||||||
lower_bound,
|
lower_bound,
|
||||||
|
multiplier_elevated_counter: 0,
|
||||||
|
time_when_logged_about_elevated_multiplier: now
|
||||||
|
- Duration::from_secs(INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS),
|
||||||
time_when_changed: now,
|
time_when_changed: now,
|
||||||
time_when_backpressure_detected: now,
|
time_when_backpressure_detected: now,
|
||||||
}
|
}
|
||||||
@@ -79,7 +95,7 @@ impl SendingDelayController {
|
|||||||
self.current_multiplier =
|
self.current_multiplier =
|
||||||
(self.current_multiplier + 1).clamp(self.lower_bound, self.upper_bound);
|
(self.current_multiplier + 1).clamp(self.lower_bound, self.upper_bound);
|
||||||
self.time_when_changed = get_time_now();
|
self.time_when_changed = get_time_now();
|
||||||
log::warn!(
|
log::debug!(
|
||||||
"Increasing sending delay multiplier to: {}",
|
"Increasing sending delay multiplier to: {}",
|
||||||
self.current_multiplier
|
self.current_multiplier
|
||||||
);
|
);
|
||||||
@@ -100,22 +116,58 @@ impl SendingDelayController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn record_backpressure_detected(&mut self) {
|
|
||||||
self.time_when_backpressure_detected = get_time_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn not_increased_delay_recently(&self) -> bool {
|
pub(crate) fn not_increased_delay_recently(&self) -> bool {
|
||||||
get_time_now()
|
get_time_now()
|
||||||
> self.time_when_changed + Duration::from_secs(INCREASE_DELAY_MIN_CHANGE_INTERVAL_SECS)
|
> self.time_when_changed + Duration::from_secs(INCREASE_DELAY_MIN_CHANGE_INTERVAL_SECS)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_sending_reliable(&self) -> bool {
|
pub(crate) fn not_decreased_delay_recently(&self) -> bool {
|
||||||
let now = get_time_now();
|
get_time_now()
|
||||||
let delay_change_interval = Duration::from_secs(DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS);
|
> self.time_when_changed + Duration::from_secs(DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS)
|
||||||
let acceptable_time_without_backpressure =
|
}
|
||||||
Duration::from_secs(ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS);
|
|
||||||
|
|
||||||
now > self.time_when_backpressure_detected + acceptable_time_without_backpressure
|
pub(crate) fn is_backpressure_currently_detected(&self, queue_length: usize) -> bool {
|
||||||
&& now > self.time_when_changed + delay_change_interval
|
queue_length > BACKPRESSURE_THRESHOLD
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn record_backpressure_detected(&mut self) {
|
||||||
|
self.time_when_backpressure_detected = get_time_now();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn was_backpressure_detected_recently(&self) -> bool {
|
||||||
|
get_time_now()
|
||||||
|
< self.time_when_backpressure_detected
|
||||||
|
+ Duration::from_secs(ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn record_delay_multiplier(&mut self) {
|
||||||
|
// Count the number of times the multiplier has been elevated.
|
||||||
|
let multiplier_elevated = self.current_multiplier - self.lower_bound;
|
||||||
|
if multiplier_elevated == 0 {
|
||||||
|
self.multiplier_elevated_counter = 0;
|
||||||
|
} else {
|
||||||
|
self.multiplier_elevated_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If needed, log about the elevated multiplier.
|
||||||
|
let now = get_time_now();
|
||||||
|
if self.multiplier_elevated_counter > 20
|
||||||
|
&& now
|
||||||
|
> self.time_when_logged_about_elevated_multiplier
|
||||||
|
+ Duration::from_secs(INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS)
|
||||||
|
{
|
||||||
|
let status_str = format!(
|
||||||
|
"Poisson delay currently scaled by: {}",
|
||||||
|
self.current_multiplier()
|
||||||
|
);
|
||||||
|
if self.current_multiplier() > 0 {
|
||||||
|
log::debug!("{}", status_str);
|
||||||
|
} else if self.current_multiplier() > 1 {
|
||||||
|
log::info!("{}", status_str);
|
||||||
|
} else if self.current_multiplier() > 2 {
|
||||||
|
log::warn!("{}", status_str);
|
||||||
|
}
|
||||||
|
self.time_when_logged_about_elevated_multiplier = now;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
|
|||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use nym_gateway_client::wasm_mockups::DirectSigningNyxdClient;
|
use nym_bandwidth_controller::wasm_mockups::DirectSigningNyxdClient;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_timer::Instant;
|
use wasm_timer::Instant;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
@@ -223,12 +224,12 @@ pub(super) async fn query_gateway_details(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn register_with_gateway(
|
pub(super) async fn register_with_gateway<St: Storage>(
|
||||||
gateway: &gateway::Node,
|
gateway: &gateway::Node,
|
||||||
our_identity: Arc<identity::KeyPair>,
|
our_identity: Arc<identity::KeyPair>,
|
||||||
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
||||||
let timeout = Duration::from_millis(1500);
|
let timeout = Duration::from_millis(1500);
|
||||||
let mut gateway_client: GatewayClient<DirectSigningNyxdClient> = GatewayClient::new_init(
|
let mut gateway_client: GatewayClient<DirectSigningNyxdClient, St> = GatewayClient::new_init(
|
||||||
gateway.clients_address(),
|
gateway.clients_address(),
|
||||||
gateway.identity_key,
|
gateway.identity_key,
|
||||||
our_identity.clone(),
|
our_identity.clone(),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use serde::Serialize;
|
|||||||
use tap::TapFallible;
|
use tap::TapFallible;
|
||||||
|
|
||||||
use nym_config::NymConfig;
|
use nym_config::NymConfig;
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
use nym_crypto::asymmetric::{encryption, identity};
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ pub fn new_client_keys() -> KeyManager {
|
|||||||
/// Either pick one at random by querying the available gateways from the nym-api, or use the
|
/// Either pick one at random by querying the available gateways from the nym-api, or use the
|
||||||
/// chosen one if it's among the available ones.
|
/// chosen one if it's among the available ones.
|
||||||
/// The shared key is added to the supplied `KeyManager` and the endpoint details are returned.
|
/// The shared key is added to the supplied `KeyManager` and the endpoint details are returned.
|
||||||
pub async fn register_with_gateway(
|
pub async fn register_with_gateway<St: Storage>(
|
||||||
key_manager: &mut KeyManager,
|
key_manager: &mut KeyManager,
|
||||||
nym_api_endpoints: Vec<Url>,
|
nym_api_endpoints: Vec<Url>,
|
||||||
chosen_gateway_id: Option<identity::PublicKey>,
|
chosen_gateway_id: Option<identity::PublicKey>,
|
||||||
@@ -87,7 +88,7 @@ pub async fn register_with_gateway(
|
|||||||
let our_identity = key_manager.identity_keypair();
|
let our_identity = key_manager.identity_keypair();
|
||||||
|
|
||||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||||
let shared_keys = helpers::register_with_gateway(&gateway, our_identity).await?;
|
let shared_keys = helpers::register_with_gateway::<St>(&gateway, our_identity).await?;
|
||||||
key_manager.insert_gateway_shared_key(shared_keys);
|
key_manager.insert_gateway_shared_key(shared_keys);
|
||||||
|
|
||||||
Ok(gateway.into())
|
Ok(gateway.into())
|
||||||
@@ -100,7 +101,7 @@ pub async fn register_with_gateway(
|
|||||||
/// b. Create a new gateway configuration but keep existing keys. This assumes that the caller
|
/// b. Create a new gateway configuration but keep existing keys. This assumes that the caller
|
||||||
/// knows what they are doing and that the keys match the requested gateway.
|
/// knows what they are doing and that the keys match the requested gateway.
|
||||||
/// c. Create a new gateway configuration with a newly registered gateway and keys.
|
/// c. Create a new gateway configuration with a newly registered gateway and keys.
|
||||||
pub async fn setup_gateway_from_config<C, T>(
|
pub async fn setup_gateway_from_config<C, T, St>(
|
||||||
register_gateway: bool,
|
register_gateway: bool,
|
||||||
user_chosen_gateway_id: Option<identity::PublicKey>,
|
user_chosen_gateway_id: Option<identity::PublicKey>,
|
||||||
config: &Config<T>,
|
config: &Config<T>,
|
||||||
@@ -109,6 +110,7 @@ pub async fn setup_gateway_from_config<C, T>(
|
|||||||
where
|
where
|
||||||
C: NymConfig + ClientCoreConfigTrait,
|
C: NymConfig + ClientCoreConfigTrait,
|
||||||
T: NymConfig,
|
T: NymConfig,
|
||||||
|
St: Storage,
|
||||||
{
|
{
|
||||||
let id = config.get_id();
|
let id = config.get_id();
|
||||||
|
|
||||||
@@ -141,7 +143,7 @@ where
|
|||||||
|
|
||||||
// Establish connection, authenticate and generate keys for talking with the gateway
|
// Establish connection, authenticate and generate keys for talking with the gateway
|
||||||
eprintln!("Registering with new gateway");
|
eprintln!("Registering with new gateway");
|
||||||
let shared_keys = helpers::register_with_gateway(&gateway, our_identity).await?;
|
let shared_keys = helpers::register_with_gateway::<St>(&gateway, our_identity).await?;
|
||||||
key_manager.insert_gateway_shared_key(shared_keys);
|
key_manager.insert_gateway_shared_key(shared_keys);
|
||||||
|
|
||||||
// Write all keys to storage and just return the gateway endpoint config. It is assumed that we
|
// Write all keys to storage and just return the gateway endpoint config. It is assumed that we
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ log = { workspace = true }
|
|||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||||
async-trait = { workspace = true }
|
|
||||||
tokio = { version = "1.24.1", features = ["macros"] }
|
tokio = { version = "1.24.1", features = ["macros"] }
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
|
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
||||||
nym-coconut-interface = { path = "../../coconut-interface" }
|
nym-coconut-interface = { path = "../../coconut-interface" }
|
||||||
nym-credentials = { path = "../../credentials" }
|
nym-credential-storage = { path = "../../credential-storage" }
|
||||||
nym-crypto = { path = "../../crypto" }
|
nym-crypto = { path = "../../crypto" }
|
||||||
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||||
nym-network-defaults = { path = "../../network-defaults" }
|
nym-network-defaults = { path = "../../network-defaults" }
|
||||||
@@ -28,7 +28,6 @@ nym-pemstore = { path = "../../pemstore" }
|
|||||||
nym-validator-client = { path = "../validator-client" }
|
nym-validator-client = { path = "../validator-client" }
|
||||||
nym-task = { path = "../../task" }
|
nym-task = { path = "../../task" }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
nym-mobile-storage = { path = "../../mobile-storage" }
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies.tungstenite]
|
[dependencies.tungstenite]
|
||||||
@@ -47,9 +46,6 @@ features = ["net", "sync", "time"]
|
|||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||||
version = "0.14"
|
version = "0.14"
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-credential-storage]
|
|
||||||
path = "../../credential-storage"
|
|
||||||
|
|
||||||
# wasm-only dependencies
|
# wasm-only dependencies
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::bandwidth::BandwidthController;
|
|
||||||
use crate::error::GatewayClientError;
|
use crate::error::GatewayClientError;
|
||||||
use crate::packet_router::PacketRouter;
|
use crate::packet_router::PacketRouter;
|
||||||
pub use crate::packet_router::{
|
pub use crate::packet_router::{
|
||||||
@@ -11,6 +10,7 @@ use crate::socket_state::{PartiallyDelegated, SocketState};
|
|||||||
use crate::{cleanup_socket_message, try_decrypt_binary_message};
|
use crate::{cleanup_socket_message, try_decrypt_binary_message};
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
use nym_coconut_interface::Credential;
|
use nym_coconut_interface::Credential;
|
||||||
use nym_crypto::asymmetric::identity;
|
use nym_crypto::asymmetric::identity;
|
||||||
use nym_gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
|
use nym_gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
|
||||||
@@ -26,24 +26,14 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tungstenite::protocol::Message;
|
use tungstenite::protocol::Message;
|
||||||
|
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
use nym_validator_client::nyxd::traits::DkgQueryClient;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use tokio_tungstenite::connect_async;
|
use tokio_tungstenite::connect_async;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
use nym_credential_storage::PersistentStorage;
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use mobile_storage::PersistentStorage;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use crate::wasm_mockups::DkgQueryClient;
|
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use crate::wasm_mockups::PersistentStorage;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_timer;
|
use wasm_timer;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
@@ -52,7 +42,7 @@ use wasm_utils::websocket::JSWebsocket;
|
|||||||
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
|
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
|
||||||
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
pub struct GatewayClient<C> {
|
pub struct GatewayClient<C, St: Storage> {
|
||||||
authenticated: bool,
|
authenticated: bool,
|
||||||
disabled_credentials_mode: bool,
|
disabled_credentials_mode: bool,
|
||||||
bandwidth_remaining: i64,
|
bandwidth_remaining: i64,
|
||||||
@@ -63,7 +53,7 @@ pub struct GatewayClient<C> {
|
|||||||
connection: SocketState,
|
connection: SocketState,
|
||||||
packet_router: PacketRouter,
|
packet_router: PacketRouter,
|
||||||
response_timeout_duration: Duration,
|
response_timeout_duration: Duration,
|
||||||
bandwidth_controller: Option<BandwidthController<C, PersistentStorage>>,
|
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||||
|
|
||||||
// reconnection related variables
|
// reconnection related variables
|
||||||
/// Specifies whether client should try to reconnect to gateway on connection failure.
|
/// Specifies whether client should try to reconnect to gateway on connection failure.
|
||||||
@@ -78,9 +68,10 @@ pub struct GatewayClient<C> {
|
|||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> GatewayClient<C>
|
impl<C, St> GatewayClient<C, St>
|
||||||
where
|
where
|
||||||
C: Sync + Send,
|
C: Sync + Send,
|
||||||
|
St: Storage,
|
||||||
{
|
{
|
||||||
// TODO: put it all in a Config struct
|
// TODO: put it all in a Config struct
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@@ -92,7 +83,7 @@ where
|
|||||||
mixnet_message_sender: MixnetMessageSender,
|
mixnet_message_sender: MixnetMessageSender,
|
||||||
ack_sender: AcknowledgementSender,
|
ack_sender: AcknowledgementSender,
|
||||||
response_timeout_duration: Duration,
|
response_timeout_duration: Duration,
|
||||||
bandwidth_controller: Option<BandwidthController<C, PersistentStorage>>,
|
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
GatewayClient {
|
GatewayClient {
|
||||||
@@ -146,7 +137,7 @@ where
|
|||||||
let shutdown = TaskClient::dummy();
|
let shutdown = TaskClient::dummy();
|
||||||
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
|
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
|
||||||
|
|
||||||
GatewayClient::<C> {
|
GatewayClient::<C, St> {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
disabled_credentials_mode: true,
|
disabled_credentials_mode: true,
|
||||||
bandwidth_remaining: 0,
|
bandwidth_remaining: 0,
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use crate::wasm_mockups::StorageError;
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
use mobile_storage::StorageError;
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
use nym_credential_storage::error::StorageError;
|
|
||||||
use nym_gateway_requests::registration::handshake::error::HandshakeError;
|
use nym_gateway_requests::registration::handshake::error::HandshakeError;
|
||||||
use std::io;
|
use std::io;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -27,12 +19,6 @@ pub enum GatewayClientError {
|
|||||||
#[error("There was a network error - {0}")]
|
#[error("There was a network error - {0}")]
|
||||||
NetworkError(#[from] WsError),
|
NetworkError(#[from] WsError),
|
||||||
|
|
||||||
#[error("There was a credential storage error - {0}")]
|
|
||||||
CredentialStorageError(#[from] StorageError),
|
|
||||||
|
|
||||||
#[error("Coconut error - {0}")]
|
|
||||||
CoconutError(#[from] nym_coconut_interface::CoconutError),
|
|
||||||
|
|
||||||
// TODO: see if `JsValue` is a reasonable type for this
|
// TODO: see if `JsValue` is a reasonable type for this
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[error("There was a network error")]
|
#[error("There was a network error")]
|
||||||
@@ -47,8 +33,8 @@ pub enum GatewayClientError {
|
|||||||
#[error("No bandwidth controller provided")]
|
#[error("No bandwidth controller provided")]
|
||||||
NoBandwidthControllerAvailable,
|
NoBandwidthControllerAvailable,
|
||||||
|
|
||||||
#[error("Credential error - {0}")]
|
#[error("Bandwidth controller error - {0}")]
|
||||||
CredentialError(#[from] nym_credentials::error::Error),
|
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
|
||||||
|
|
||||||
#[error("Connection was abruptly closed")]
|
#[error("Connection was abruptly closed")]
|
||||||
ConnectionAbruptlyClosed,
|
ConnectionAbruptlyClosed,
|
||||||
|
|||||||
@@ -11,13 +11,10 @@ pub use packet_router::{
|
|||||||
};
|
};
|
||||||
use tungstenite::{protocol::Message, Error as WsError};
|
use tungstenite::{protocol::Message, Error as WsError};
|
||||||
|
|
||||||
pub mod bandwidth;
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod packet_router;
|
pub mod packet_router;
|
||||||
pub mod socket_state;
|
pub mod socket_state;
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
pub mod wasm_mockups;
|
|
||||||
|
|
||||||
/// Helper method for reading from websocket stream. Helps to flatten the structure.
|
/// Helper method for reading from websocket stream. Helps to flatten the structure.
|
||||||
pub(crate) fn cleanup_socket_message(
|
pub(crate) fn cleanup_socket_message(
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum StorageError {
|
|
||||||
#[error("Wasm client is not yet supported")]
|
|
||||||
WasmNotSupported,
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[error("Code shouldn't reach this point")]
|
|
||||||
InconsistentData,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DirectSigningNyxdClient {}
|
|
||||||
|
|
||||||
pub trait DkgQueryClient {}
|
|
||||||
|
|
||||||
// impl CosmWasmClient for DirectSigningNyxdClient {}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Client<C> {
|
|
||||||
_phantom: PhantomData<C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> DkgQueryClient for Client<C> {}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PersistentStorage {}
|
|
||||||
|
|
||||||
pub struct CoconutCredential {
|
|
||||||
pub id: i64,
|
|
||||||
pub voucher_value: String,
|
|
||||||
pub voucher_info: String,
|
|
||||||
pub serial_number: String,
|
|
||||||
pub binding_number: String,
|
|
||||||
pub signature: String,
|
|
||||||
pub epoch_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Storage: Send + Sync {
|
|
||||||
async fn insert_coconut_credential(
|
|
||||||
&self,
|
|
||||||
voucher_value: String,
|
|
||||||
voucher_info: String,
|
|
||||||
serial_number: String,
|
|
||||||
binding_number: String,
|
|
||||||
signature: String,
|
|
||||||
) -> Result<(), StorageError>;
|
|
||||||
|
|
||||||
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError>;
|
|
||||||
|
|
||||||
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Storage for PersistentStorage {
|
|
||||||
async fn insert_coconut_credential(
|
|
||||||
&self,
|
|
||||||
_voucher_value: String,
|
|
||||||
_voucher_info: String,
|
|
||||||
_serial_number: String,
|
|
||||||
_binding_number: String,
|
|
||||||
_signature: String,
|
|
||||||
) -> Result<(), StorageError> {
|
|
||||||
Err(StorageError::WasmNotSupported)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
|
|
||||||
Err(StorageError::WasmNotSupported)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn consume_coconut_credential(&self, _id: i64) -> Result<(), StorageError> {
|
|
||||||
Err(StorageError::WasmNotSupported)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
#[cfg(feature = "nyxd-client")]
|
#[cfg(feature = "nyxd-client")]
|
||||||
pub mod connection_tester;
|
pub mod connection_tester;
|
||||||
mod error;
|
pub mod error;
|
||||||
pub mod nym_api;
|
pub mod nym_api;
|
||||||
#[cfg(feature = "nyxd-client")]
|
#[cfg(feature = "nyxd-client")]
|
||||||
pub mod nyxd;
|
pub mod nyxd;
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ use nym_mixnet_contract_common::{
|
|||||||
MixOwnershipResponse, MixnodeDetailsResponse, NumberOfPendingEventsResponse,
|
MixOwnershipResponse, MixnodeDetailsResponse, NumberOfPendingEventsResponse,
|
||||||
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedFamiliesResponse,
|
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedFamiliesResponse,
|
||||||
PagedGatewayResponse, PagedMembersResponse, PagedMixNodeDelegationsResponse,
|
PagedGatewayResponse, PagedMembersResponse, PagedMixNodeDelegationsResponse,
|
||||||
PagedMixnodeBondsResponse, PagedRewardedSetResponse, PendingEpochEventsResponse,
|
PagedMixnodeBondsResponse, PagedRewardedSetResponse, PendingEpochEventResponse,
|
||||||
PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
|
PendingEpochEventsResponse, PendingIntervalEventResponse, PendingIntervalEventsResponse,
|
||||||
|
QueryMsg as MixnetQueryMsg,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
@@ -174,6 +175,16 @@ pub trait MixnetQueryClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_mixnode_details_by_identity(
|
||||||
|
&self,
|
||||||
|
mix_identity: IdentityKey,
|
||||||
|
) -> Result<Option<MixNodeDetails>, NyxdError> {
|
||||||
|
self.query_mixnet_contract(MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity {
|
||||||
|
mix_identity,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_mixnode_rewarding_details(
|
async fn get_mixnode_rewarding_details(
|
||||||
&self,
|
&self,
|
||||||
mix_id: MixId,
|
mix_id: MixId,
|
||||||
@@ -374,14 +385,20 @@ pub trait MixnetQueryClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_mixnode_details_by_identity(
|
async fn get_pending_epoch_event(
|
||||||
&self,
|
&self,
|
||||||
mix_identity: IdentityKey,
|
event_id: EpochEventId,
|
||||||
) -> Result<Option<MixNodeDetails>, NyxdError> {
|
) -> Result<PendingEpochEventResponse, NyxdError> {
|
||||||
self.query_mixnet_contract(MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity {
|
self.query_mixnet_contract(MixnetQueryMsg::GetPendingEpochEvent { event_id })
|
||||||
mix_identity,
|
.await
|
||||||
})
|
}
|
||||||
.await
|
|
||||||
|
async fn get_pending_interval_event(
|
||||||
|
&self,
|
||||||
|
event_id: IntervalEventId,
|
||||||
|
) -> Result<PendingIntervalEventResponse, NyxdError> {
|
||||||
|
self.query_mixnet_contract(MixnetQueryMsg::GetPendingIntervalEvent { event_id })
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_number_of_pending_events(
|
async fn get_number_of_pending_events(
|
||||||
|
|||||||
@@ -331,6 +331,38 @@ pub trait MixnetSigningClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn decrease_pledge(
|
||||||
|
&self,
|
||||||
|
decrease_by: Coin,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NyxdError> {
|
||||||
|
self.execute_mixnet_contract(
|
||||||
|
fee,
|
||||||
|
MixnetExecuteMsg::DecreasePledge {
|
||||||
|
decrease_by: decrease_by.into(),
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn decrease_pledge_on_behalf(
|
||||||
|
&self,
|
||||||
|
owner: AccountId,
|
||||||
|
decrease_by: Coin,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NyxdError> {
|
||||||
|
self.execute_mixnet_contract(
|
||||||
|
fee,
|
||||||
|
MixnetExecuteMsg::DecreasePledgeOnBehalf {
|
||||||
|
owner: owner.to_string(),
|
||||||
|
decrease_by: decrease_by.into(),
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
async fn unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondMixnode {}, vec![])
|
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondMixnode {}, vec![])
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -91,6 +91,21 @@ pub trait VestingSigningClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn vesting_decrease_pledge(
|
||||||
|
&self,
|
||||||
|
decrease_by: Coin,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NyxdError> {
|
||||||
|
self.execute_vesting_contract(
|
||||||
|
fee,
|
||||||
|
VestingExecuteMsg::DecreasePledge {
|
||||||
|
amount: decrease_by.into(),
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError>;
|
async fn vesting_unbond_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError>;
|
||||||
|
|
||||||
async fn vesting_track_unbond_mixnode(
|
async fn vesting_track_unbond_mixnode(
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub struct Args {
|
|||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
value_parser,
|
value_parser,
|
||||||
requires = "fundsDenom",
|
requires = "funds_denom",
|
||||||
help = "Amount to supply as funds in micro denomination (e.g. unym or unyx)"
|
help = "Amount to supply as funds in micro denomination (e.g. unym or unyx)"
|
||||||
)]
|
)]
|
||||||
pub funds: Option<u128>,
|
pub funds: Option<u128>,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pub struct Args {
|
|||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
long,
|
long,
|
||||||
requires = "fundsDenom",
|
requires = "funds_denom",
|
||||||
help = "Amount to supply as funds in micro denomination (e.g. unym or unyx)"
|
help = "Amount to supply as funds in micro denomination (e.g. unym or unyx)"
|
||||||
)]
|
)]
|
||||||
pub funds: Option<u128>,
|
pub funds: Option<u128>,
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ use clap::{Args, Subcommand};
|
|||||||
pub mod rewards;
|
pub mod rewards;
|
||||||
|
|
||||||
pub mod delegate_to_mixnode;
|
pub mod delegate_to_mixnode;
|
||||||
pub mod pledge_more;
|
|
||||||
pub mod query_for_delegations;
|
pub mod query_for_delegations;
|
||||||
pub mod undelegate_from_mixnode;
|
pub mod undelegate_from_mixnode;
|
||||||
pub mod vesting_delegate_to_mixnode;
|
pub mod vesting_delegate_to_mixnode;
|
||||||
pub mod vesting_pledge_more;
|
|
||||||
pub mod vesting_undelegate_from_mixnode;
|
pub mod vesting_undelegate_from_mixnode;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
@@ -34,8 +32,4 @@ pub enum MixnetDelegatorsCommands {
|
|||||||
DelegateVesting(vesting_delegate_to_mixnode::Args),
|
DelegateVesting(vesting_delegate_to_mixnode::Args),
|
||||||
/// Undelegate from a mixnode (when originally using locked tokens)
|
/// Undelegate from a mixnode (when originally using locked tokens)
|
||||||
UndelegateVesting(vesting_undelegate_from_mixnode::Args),
|
UndelegateVesting(vesting_undelegate_from_mixnode::Args),
|
||||||
/// Pledge more
|
|
||||||
PledgeMore(pledge_more::Args),
|
|
||||||
/// Pledge more with locked tokens
|
|
||||||
PledgeMoreVesting(vesting_pledge_more::Args),
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ pub struct Args {
|
|||||||
pub version: Option<String>,
|
pub version: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn vesting_update_config(client: SigningClient, args: Args) {
|
pub async fn vesting_update_config(args: Args, client: SigningClient) {
|
||||||
info!("Update vesting gateway config!");
|
info!("Update vesting gateway config!");
|
||||||
|
|
||||||
let current_details = match client
|
let current_details = match client
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ pub struct Args {
|
|||||||
pub force: bool,
|
pub force: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn vesting_bond_gateway(client: SigningClient, args: Args, denom: &str) {
|
pub async fn vesting_bond_gateway(args: Args, client: SigningClient) {
|
||||||
|
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||||
|
|
||||||
info!("Starting vesting gateway bonding!");
|
info!("Starting vesting gateway bonding!");
|
||||||
|
|
||||||
// if we're trying to bond less than 1 token
|
// if we're trying to bond less than 1 token
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2023 - 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::Coin;
|
||||||
|
use nym_validator_client::nyxd::traits::MixnetSigningClient;
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
pub struct Args {
|
||||||
|
#[clap(long)]
|
||||||
|
pub decrease_by: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn decrease_pledge(args: Args, client: SigningClient) {
|
||||||
|
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||||
|
|
||||||
|
info!("Starting to decrease pledge");
|
||||||
|
|
||||||
|
let coin = Coin::new(args.decrease_by, denom);
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.pledge_more(coin.into(), None)
|
||||||
|
.await
|
||||||
|
.expect("failed to decrease pledge!");
|
||||||
|
|
||||||
|
info!("decreasing pledge: {:?}", res);
|
||||||
|
}
|
||||||
@@ -4,13 +4,17 @@
|
|||||||
use clap::{Args, Subcommand};
|
use clap::{Args, Subcommand};
|
||||||
|
|
||||||
pub mod bond_mixnode;
|
pub mod bond_mixnode;
|
||||||
|
pub mod decrease_pledge;
|
||||||
pub mod families;
|
pub mod families;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod mixnode_bonding_sign_payload;
|
pub mod mixnode_bonding_sign_payload;
|
||||||
|
pub mod pledge_more;
|
||||||
pub mod rewards;
|
pub mod rewards;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod unbond_mixnode;
|
pub mod unbond_mixnode;
|
||||||
pub mod vesting_bond_mixnode;
|
pub mod vesting_bond_mixnode;
|
||||||
|
pub mod vesting_decrease_pledge;
|
||||||
|
pub mod vesting_pledge_more;
|
||||||
pub mod vesting_unbond_mixnode;
|
pub mod vesting_unbond_mixnode;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
@@ -40,4 +44,12 @@ pub enum MixnetOperatorsMixnodeCommands {
|
|||||||
UnbondVesting(vesting_unbond_mixnode::Args),
|
UnbondVesting(vesting_unbond_mixnode::Args),
|
||||||
/// Create base58-encoded payload required for producing valid bonding signature.
|
/// Create base58-encoded payload required for producing valid bonding signature.
|
||||||
CreateMixnodeBondingSignPayload(mixnode_bonding_sign_payload::Args),
|
CreateMixnodeBondingSignPayload(mixnode_bonding_sign_payload::Args),
|
||||||
|
/// Pledge more
|
||||||
|
PledgeMore(pledge_more::Args),
|
||||||
|
/// Pledge more with locked tokens
|
||||||
|
PledgeMoreVesting(vesting_pledge_more::Args),
|
||||||
|
/// Decrease pledge
|
||||||
|
DecreasePledge(decrease_pledge::Args),
|
||||||
|
/// Decrease pledge with locked tokens
|
||||||
|
DecreasePledgeVesting(vesting_decrease_pledge::Args),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2023 - 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::Coin;
|
||||||
|
use nym_validator_client::nyxd::VestingSigningClient;
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
pub struct Args {
|
||||||
|
#[clap(long)]
|
||||||
|
pub decrease_by: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn vesting_decrease_pledge(args: Args, client: SigningClient) {
|
||||||
|
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||||
|
|
||||||
|
info!("Starting vesting to decrease pledge");
|
||||||
|
|
||||||
|
let coin = Coin::new(args.decrease_by, denom);
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.vesting_decrease_pledge(coin.into(), None)
|
||||||
|
.await
|
||||||
|
.expect("failed to vesting decrease pledge!");
|
||||||
|
|
||||||
|
info!("vesting decreasing pledge: {:?}", res);
|
||||||
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{EpochState, IdentityKey, MixId};
|
use crate::{EpochEventId, EpochState, IdentityKey, MixId};
|
||||||
use contracts_common::signing::verifier::ApiVerifierError;
|
use contracts_common::signing::verifier::ApiVerifierError;
|
||||||
use cosmwasm_std::{Addr, Coin, Decimal};
|
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
pub enum MixnetContractError {
|
pub enum MixnetContractError {
|
||||||
|
#[error("could not perform contract migration: {comment}")]
|
||||||
|
FailedMigration { comment: String },
|
||||||
|
|
||||||
#[error("{source}")]
|
#[error("{source}")]
|
||||||
StdErr {
|
StdErr {
|
||||||
#[from]
|
#[from]
|
||||||
@@ -26,6 +29,17 @@ pub enum MixnetContractError {
|
|||||||
#[error("Not enough funds sent for node pledge. (received {received}, minimum {minimum})")]
|
#[error("Not enough funds sent for node pledge. (received {received}, minimum {minimum})")]
|
||||||
InsufficientPledge { received: Coin, minimum: Coin },
|
InsufficientPledge { received: Coin, minimum: Coin },
|
||||||
|
|
||||||
|
#[error("Attempted to reduce node pledge ({current}{denom} - {decrease_by}{denom}) below the minimum amount: {minimum}{denom}")]
|
||||||
|
InvalidPledgeReduction {
|
||||||
|
current: Uint128,
|
||||||
|
decrease_by: Uint128,
|
||||||
|
minimum: Uint128,
|
||||||
|
denom: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[error("A pledge change is already pending in this epoch. The event id: {pending_event_id}")]
|
||||||
|
PendingPledgeChange { pending_event_id: EpochEventId },
|
||||||
|
|
||||||
#[error("Not enough funds sent for node delegation. (received {received}, minimum {minimum})")]
|
#[error("Not enough funds sent for node delegation. (received {received}, minimum {minimum})")]
|
||||||
InsufficientDelegation { received: Coin, minimum: Coin },
|
InsufficientDelegation { received: Coin, minimum: Coin },
|
||||||
|
|
||||||
@@ -190,6 +204,9 @@ pub enum MixnetContractError {
|
|||||||
#[error("epoch duration must be > 0")]
|
#[error("epoch duration must be > 0")]
|
||||||
EpochDurationZero,
|
EpochDurationZero,
|
||||||
|
|
||||||
|
#[error("attempted to perform the operation with 0 coins. This is not allowed")]
|
||||||
|
ZeroCoinAmount,
|
||||||
|
|
||||||
#[error("this validator ({current_validator}) is not the one responsible for advancing this epoch. It's responsibility of {chosen_validator}.")]
|
#[error("this validator ({current_validator}) is not the one responsible for advancing this epoch. It's responsibility of {chosen_validator}.")]
|
||||||
RewardingValidatorMismatch {
|
RewardingValidatorMismatch {
|
||||||
current_validator: Addr,
|
current_validator: Addr,
|
||||||
@@ -226,3 +243,11 @@ pub enum MixnetContractError {
|
|||||||
source: ApiVerifierError,
|
source: ApiVerifierError,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MixnetContractError {
|
||||||
|
pub fn inconsistent_state<S: Into<String>>(comment: S) -> Self {
|
||||||
|
MixnetContractError::InconsistentState {
|
||||||
|
comment: comment.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ pub enum MixnetEventType {
|
|||||||
MixnodeBonding,
|
MixnodeBonding,
|
||||||
PendingPledgeIncrease,
|
PendingPledgeIncrease,
|
||||||
PledgeIncrease,
|
PledgeIncrease,
|
||||||
|
PendingPledgeDecrease,
|
||||||
|
PledgeDecrease,
|
||||||
GatewayBonding,
|
GatewayBonding,
|
||||||
GatewayUnbonding,
|
GatewayUnbonding,
|
||||||
PendingMixnodeUnbonding,
|
PendingMixnodeUnbonding,
|
||||||
@@ -58,6 +60,8 @@ impl ToString for MixnetEventType {
|
|||||||
MixnetEventType::MixnodeBonding => "mixnode_bonding",
|
MixnetEventType::MixnodeBonding => "mixnode_bonding",
|
||||||
MixnetEventType::PendingPledgeIncrease => "pending_pledge_increase",
|
MixnetEventType::PendingPledgeIncrease => "pending_pledge_increase",
|
||||||
MixnetEventType::PledgeIncrease => "pledge_increase",
|
MixnetEventType::PledgeIncrease => "pledge_increase",
|
||||||
|
MixnetEventType::PendingPledgeDecrease => "pending_pledge_decrease",
|
||||||
|
MixnetEventType::PledgeDecrease => "pledge_decrease",
|
||||||
MixnetEventType::GatewayBonding => "gateway_bonding",
|
MixnetEventType::GatewayBonding => "gateway_bonding",
|
||||||
MixnetEventType::GatewayUnbonding => "gateway_unbonding",
|
MixnetEventType::GatewayUnbonding => "gateway_unbonding",
|
||||||
MixnetEventType::PendingMixnodeUnbonding => "pending_mixnode_unbonding",
|
MixnetEventType::PendingMixnodeUnbonding => "pending_mixnode_unbonding",
|
||||||
@@ -354,6 +358,19 @@ pub fn new_pledge_increase_event(created_at: BlockHeight, mix_id: MixId, amount:
|
|||||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_pending_pledge_decrease_event(mix_id: MixId, amount: &Coin) -> Event {
|
||||||
|
Event::new(MixnetEventType::PendingPledgeDecrease)
|
||||||
|
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||||
|
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_pledge_decrease_event(created_at: BlockHeight, mix_id: MixId, amount: &Coin) -> Event {
|
||||||
|
Event::new(MixnetEventType::PledgeDecrease)
|
||||||
|
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
||||||
|
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||||
|
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Event {
|
pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Event {
|
||||||
Event::new(MixnetEventType::MixnodeUnbonding)
|
Event::new(MixnetEventType::MixnodeUnbonding)
|
||||||
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
use crate::error::MixnetContractError;
|
use crate::error::MixnetContractError;
|
||||||
use crate::pending_events::{PendingEpochEvent, PendingIntervalEvent};
|
use crate::pending_events::{PendingEpochEvent, PendingIntervalEvent};
|
||||||
use crate::{EpochId, IntervalId, MixId};
|
use crate::{
|
||||||
|
EpochEventId, EpochId, IntervalEventId, IntervalId, MixId, PendingEpochEventData,
|
||||||
|
PendingIntervalEventData,
|
||||||
|
};
|
||||||
use cosmwasm_std::{Addr, Env};
|
use cosmwasm_std::{Addr, Env};
|
||||||
use schemars::gen::SchemaGenerator;
|
use schemars::gen::SchemaGenerator;
|
||||||
use schemars::schema::{InstanceType, Schema, SchemaObject};
|
use schemars::schema::{InstanceType, Schema, SchemaObject};
|
||||||
@@ -528,6 +531,30 @@ impl PendingIntervalEventsResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct PendingEpochEventResponse {
|
||||||
|
pub event_id: EpochEventId,
|
||||||
|
pub event: Option<PendingEpochEventData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingEpochEventResponse {
|
||||||
|
pub fn new(event_id: EpochEventId, event: Option<PendingEpochEventData>) -> Self {
|
||||||
|
PendingEpochEventResponse { event_id, event }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct PendingIntervalEventResponse {
|
||||||
|
pub event_id: IntervalEventId,
|
||||||
|
pub event: Option<PendingIntervalEventData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingIntervalEventResponse {
|
||||||
|
pub fn new(event_id: IntervalEventId, event: Option<PendingIntervalEventData>) -> Self {
|
||||||
|
PendingIntervalEventResponse { event_id, event }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct NumberOfPendingEventsResponse {
|
pub struct NumberOfPendingEventsResponse {
|
||||||
pub epoch_events: u32,
|
pub epoch_events: u32,
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ pub use gateway::{
|
|||||||
};
|
};
|
||||||
pub use interval::{
|
pub use interval::{
|
||||||
CurrentIntervalResponse, EpochState, EpochStatus, Interval, NumberOfPendingEventsResponse,
|
CurrentIntervalResponse, EpochState, EpochStatus, Interval, NumberOfPendingEventsResponse,
|
||||||
PendingEpochEventsResponse, PendingIntervalEventsResponse,
|
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEventResponse,
|
||||||
|
PendingIntervalEventsResponse,
|
||||||
};
|
};
|
||||||
pub use mixnode::{
|
pub use mixnode::{
|
||||||
Layer, MixNode, MixNodeBond, MixNodeConfigUpdate, MixNodeCostParams, MixNodeDetails,
|
Layer, MixNode, MixNodeBond, MixNodeConfigUpdate, MixNodeCostParams, MixNodeDetails,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::helpers::IntoBaseDecimal;
|
|||||||
use crate::reward_params::{NodeRewardParams, RewardingParams};
|
use crate::reward_params::{NodeRewardParams, RewardingParams};
|
||||||
use crate::rewarding::helpers::truncate_reward;
|
use crate::rewarding::helpers::truncate_reward;
|
||||||
use crate::rewarding::RewardDistribution;
|
use crate::rewarding::RewardDistribution;
|
||||||
use crate::{Delegation, EpochId, IdentityKey, MixId, Percent, SphinxKey};
|
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
|
||||||
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
|
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -37,13 +37,20 @@ impl RewardedSetNodeStatus {
|
|||||||
pub struct MixNodeDetails {
|
pub struct MixNodeDetails {
|
||||||
pub bond_information: MixNodeBond,
|
pub bond_information: MixNodeBond,
|
||||||
pub rewarding_details: MixNodeRewarding,
|
pub rewarding_details: MixNodeRewarding,
|
||||||
|
#[serde(default)]
|
||||||
|
pub pending_changes: PendingMixNodeChanges,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MixNodeDetails {
|
impl MixNodeDetails {
|
||||||
pub fn new(bond_information: MixNodeBond, rewarding_details: MixNodeRewarding) -> Self {
|
pub fn new(
|
||||||
|
bond_information: MixNodeBond,
|
||||||
|
rewarding_details: MixNodeRewarding,
|
||||||
|
pending_changes: PendingMixNodeChanges,
|
||||||
|
) -> Self {
|
||||||
MixNodeDetails {
|
MixNodeDetails {
|
||||||
bond_information,
|
bond_information,
|
||||||
rewarding_details,
|
rewarding_details,
|
||||||
|
pending_changes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +80,10 @@ impl MixNodeDetails {
|
|||||||
pub fn total_stake(&self) -> Decimal {
|
pub fn total_stake(&self) -> Decimal {
|
||||||
self.rewarding_details.node_bond()
|
self.rewarding_details.node_bond()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pending_pledge_change(&self) -> Option<EpochEventId> {
|
||||||
|
self.pending_changes.pledge_change
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
@@ -332,6 +343,22 @@ impl MixNodeRewarding {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decreases total pledge of operator by the specified amount.
|
||||||
|
pub fn decrease_operator_uint128(
|
||||||
|
&mut self,
|
||||||
|
amount: Uint128,
|
||||||
|
) -> Result<(), MixnetContractError> {
|
||||||
|
let amount_decimal = amount.into_base_decimal()?;
|
||||||
|
if self.operator < amount_decimal {
|
||||||
|
return Err(MixnetContractError::OverflowDecimalSubtraction {
|
||||||
|
minuend: self.operator,
|
||||||
|
subtrahend: amount_decimal,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.operator -= amount_decimal;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increase_delegates_uint128(
|
pub fn increase_delegates_uint128(
|
||||||
&mut self,
|
&mut self,
|
||||||
amount: Uint128,
|
amount: Uint128,
|
||||||
@@ -601,6 +628,25 @@ impl From<Layer> for u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "generate-ts",
|
||||||
|
ts(export_to = "ts-packages/types/src/types/rust/PendingMixnodeChanges.ts")
|
||||||
|
)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||||
|
pub struct PendingMixNodeChanges {
|
||||||
|
pub pledge_change: Option<EpochEventId>,
|
||||||
|
// pub cost_params_change: Option<IntervalEventId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingMixNodeChanges {
|
||||||
|
pub fn new_empty() -> PendingMixNodeChanges {
|
||||||
|
PendingMixNodeChanges {
|
||||||
|
pledge_change: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "generate-ts",
|
feature = "generate-ts",
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
|||||||
use crate::reward_params::{
|
use crate::reward_params::{
|
||||||
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
|
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
|
||||||
};
|
};
|
||||||
use crate::{delegation, ContractStateParams, Layer, LayerAssignment, MixId, Percent};
|
use crate::{
|
||||||
|
delegation, ContractStateParams, EpochEventId, IntervalEventId, Layer, LayerAssignment, MixId,
|
||||||
|
Percent,
|
||||||
|
};
|
||||||
use crate::{Gateway, IdentityKey, MixNode};
|
use crate::{Gateway, IdentityKey, MixNode};
|
||||||
use contracts_common::signing::MessageSignature;
|
use contracts_common::signing::MessageSignature;
|
||||||
use cosmwasm_std::Decimal;
|
use cosmwasm_std::{Coin, Decimal};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -161,6 +164,13 @@ pub enum ExecuteMsg {
|
|||||||
PledgeMoreOnBehalf {
|
PledgeMoreOnBehalf {
|
||||||
owner: String,
|
owner: String,
|
||||||
},
|
},
|
||||||
|
DecreasePledge {
|
||||||
|
decrease_by: Coin,
|
||||||
|
},
|
||||||
|
DecreasePledgeOnBehalf {
|
||||||
|
owner: String,
|
||||||
|
decrease_by: Coin,
|
||||||
|
},
|
||||||
UnbondMixnode {},
|
UnbondMixnode {},
|
||||||
UnbondMixnodeOnBehalf {
|
UnbondMixnodeOnBehalf {
|
||||||
owner: String,
|
owner: String,
|
||||||
@@ -297,6 +307,10 @@ impl ExecuteMsg {
|
|||||||
}
|
}
|
||||||
ExecuteMsg::PledgeMore {} => "pledging additional tokens".into(),
|
ExecuteMsg::PledgeMore {} => "pledging additional tokens".into(),
|
||||||
ExecuteMsg::PledgeMoreOnBehalf { .. } => "pledging additional tokens on behalf".into(),
|
ExecuteMsg::PledgeMoreOnBehalf { .. } => "pledging additional tokens on behalf".into(),
|
||||||
|
ExecuteMsg::DecreasePledge { .. } => "decreasing mixnode pledge".into(),
|
||||||
|
ExecuteMsg::DecreasePledgeOnBehalf { .. } => {
|
||||||
|
"decreasing mixnode pledge on behalf".into()
|
||||||
|
}
|
||||||
ExecuteMsg::UnbondMixnode { .. } => "unbonding mixnode".into(),
|
ExecuteMsg::UnbondMixnode { .. } => "unbonding mixnode".into(),
|
||||||
ExecuteMsg::UnbondMixnodeOnBehalf { .. } => "unbonding mixnode on behalf".into(),
|
ExecuteMsg::UnbondMixnodeOnBehalf { .. } => "unbonding mixnode on behalf".into(),
|
||||||
ExecuteMsg::UpdateMixnodeCostParams { .. } => "updating mixnode cost parameters".into(),
|
ExecuteMsg::UpdateMixnodeCostParams { .. } => "updating mixnode cost parameters".into(),
|
||||||
@@ -506,6 +520,12 @@ pub enum QueryMsg {
|
|||||||
limit: Option<u32>,
|
limit: Option<u32>,
|
||||||
start_after: Option<u32>,
|
start_after: Option<u32>,
|
||||||
},
|
},
|
||||||
|
GetPendingEpochEvent {
|
||||||
|
event_id: EpochEventId,
|
||||||
|
},
|
||||||
|
GetPendingIntervalEvent {
|
||||||
|
event_id: IntervalEventId,
|
||||||
|
},
|
||||||
GetNumberOfPendingEvents {},
|
GetNumberOfPendingEvents {},
|
||||||
|
|
||||||
// signing-related
|
// signing-related
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ pub enum PendingEpochEventKind {
|
|||||||
mix_id: MixId,
|
mix_id: MixId,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
},
|
},
|
||||||
|
DecreasePledge {
|
||||||
|
mix_id: MixId,
|
||||||
|
decrease_by: Coin,
|
||||||
|
},
|
||||||
UnbondMixnode {
|
UnbondMixnode {
|
||||||
mix_id: MixId,
|
mix_id: MixId,
|
||||||
},
|
},
|
||||||
@@ -66,7 +70,7 @@ impl From<(EpochEventId, PendingEpochEventData)> for PendingEpochEvent {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct PendingIntervalEvent {
|
pub struct PendingIntervalEvent {
|
||||||
pub id: EpochEventId,
|
pub id: IntervalEventId,
|
||||||
pub event: PendingIntervalEventData,
|
pub event: PendingIntervalEventData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
|
pub mod response;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
// Re-export all types at the top-level
|
// Re-export all types at the top-level
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{NymAddress, Service, ServiceId, ServiceType};
|
use crate::{NymAddress, ServiceId, ServiceType};
|
||||||
use cosmwasm_std::{Addr, Coin};
|
use cosmwasm_std::Coin;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
@@ -48,10 +48,10 @@ pub enum QueryMsg {
|
|||||||
ServiceId {
|
ServiceId {
|
||||||
service_id: ServiceId,
|
service_id: ServiceId,
|
||||||
},
|
},
|
||||||
Announcer {
|
ByAnnouncer {
|
||||||
announcer: Addr,
|
announcer: String,
|
||||||
},
|
},
|
||||||
NymAddress {
|
ByNymAddress {
|
||||||
nym_address: NymAddress,
|
nym_address: NymAddress,
|
||||||
},
|
},
|
||||||
All {
|
All {
|
||||||
@@ -72,77 +72,3 @@ impl QueryMsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub struct ServiceInfo {
|
|
||||||
pub service_id: ServiceId,
|
|
||||||
pub service: Service,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ServiceInfo {
|
|
||||||
pub fn new(service_id: ServiceId, service: Service) -> Self {
|
|
||||||
Self {
|
|
||||||
service_id,
|
|
||||||
service,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub struct ServicesListResponse {
|
|
||||||
pub services: Vec<ServiceInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ServicesListResponse {
|
|
||||||
pub fn new(services: Vec<(ServiceId, Service)>) -> ServicesListResponse {
|
|
||||||
ServicesListResponse {
|
|
||||||
services: services
|
|
||||||
.into_iter()
|
|
||||||
.map(|(service_id, service)| ServiceInfo::new(service_id, service))
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub struct PagedServicesListResponse {
|
|
||||||
pub services: Vec<ServiceInfo>,
|
|
||||||
pub per_page: usize,
|
|
||||||
pub start_next_after: Option<ServiceId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PagedServicesListResponse {
|
|
||||||
pub fn new(
|
|
||||||
services: Vec<(ServiceId, Service)>,
|
|
||||||
per_page: usize,
|
|
||||||
start_next_after: Option<ServiceId>,
|
|
||||||
) -> PagedServicesListResponse {
|
|
||||||
let services = services
|
|
||||||
.into_iter()
|
|
||||||
.map(|(service_id, service)| ServiceInfo::new(service_id, service))
|
|
||||||
.collect();
|
|
||||||
PagedServicesListResponse {
|
|
||||||
services,
|
|
||||||
per_page,
|
|
||||||
start_next_after,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub struct ConfigResponse {
|
|
||||||
pub deposit_required: Coin,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Service> for ExecuteMsg {
|
|
||||||
fn from(service: Service) -> Self {
|
|
||||||
ExecuteMsg::Announce {
|
|
||||||
nym_address: service.nym_address,
|
|
||||||
service_type: service.service_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
use crate::{msg::ExecuteMsg, Service, ServiceId, ServiceInfo};
|
||||||
|
use cosmwasm_std::Coin;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct ServiceInfoResponse {
|
||||||
|
pub service_id: ServiceId,
|
||||||
|
pub service: Option<Service>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct ServicesListResponse {
|
||||||
|
pub services: Vec<ServiceInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServicesListResponse {
|
||||||
|
pub fn new(services: Vec<(ServiceId, Service)>) -> ServicesListResponse {
|
||||||
|
ServicesListResponse {
|
||||||
|
services: services
|
||||||
|
.into_iter()
|
||||||
|
.map(|(service_id, service)| ServiceInfo::new(service_id, service))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct PagedServicesListResponse {
|
||||||
|
pub services: Vec<ServiceInfo>,
|
||||||
|
pub per_page: usize,
|
||||||
|
pub start_next_after: Option<ServiceId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PagedServicesListResponse {
|
||||||
|
pub fn new(
|
||||||
|
services: Vec<(ServiceId, Service)>,
|
||||||
|
per_page: usize,
|
||||||
|
start_next_after: Option<ServiceId>,
|
||||||
|
) -> PagedServicesListResponse {
|
||||||
|
let services = services
|
||||||
|
.into_iter()
|
||||||
|
.map(|(service_id, service)| ServiceInfo::new(service_id, service))
|
||||||
|
.collect();
|
||||||
|
PagedServicesListResponse {
|
||||||
|
services,
|
||||||
|
per_page,
|
||||||
|
start_next_after,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct ConfigResponse {
|
||||||
|
pub deposit_required: Coin,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Service> for ExecuteMsg {
|
||||||
|
fn from(service: Service) -> Self {
|
||||||
|
ExecuteMsg::Announce {
|
||||||
|
nym_address: service.nym_address,
|
||||||
|
service_type: service.service_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,3 +65,19 @@ impl std::fmt::Display for ServiceType {
|
|||||||
write!(f, "{service_type}")
|
write!(f, "{service_type}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct ServiceInfo {
|
||||||
|
pub service_id: ServiceId,
|
||||||
|
pub service: Service,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServiceInfo {
|
||||||
|
pub fn new(service_id: ServiceId, service: Service) -> Self {
|
||||||
|
Self {
|
||||||
|
service_id,
|
||||||
|
service,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub const VESTING_GATEWAY_BONDING_EVENT_TYPE: &str = "vesting_gateway_bonding";
|
|||||||
pub const VESTING_GATEWAY_UNBONDING_EVENT_TYPE: &str = "vesting_gateway_unbonding";
|
pub const VESTING_GATEWAY_UNBONDING_EVENT_TYPE: &str = "vesting_gateway_unbonding";
|
||||||
pub const VESTING_MIXNODE_BONDING_EVENT_TYPE: &str = "vesting_mixnode_bonding";
|
pub const VESTING_MIXNODE_BONDING_EVENT_TYPE: &str = "vesting_mixnode_bonding";
|
||||||
pub const VESTING_PLEDGE_MORE_EVENT_TYPE: &str = "vesting_pledge_more";
|
pub const VESTING_PLEDGE_MORE_EVENT_TYPE: &str = "vesting_pledge_more";
|
||||||
|
pub const VESTING_DECREASE_PLEDGE_EVENT_TYPE: &str = "vesting_pledge_decrease";
|
||||||
pub const VESTING_MIXNODE_UNBONDING_EVENT_TYPE: &str = "vesting_mixnode_unbonding";
|
pub const VESTING_MIXNODE_UNBONDING_EVENT_TYPE: &str = "vesting_mixnode_unbonding";
|
||||||
pub const VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE: &str = "vesting_update_mixnode_config";
|
pub const VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE: &str = "vesting_update_mixnode_config";
|
||||||
pub const VESTING_UPDATE_GATEWAY_CONFIG_EVENT_TYPE: &str = "vesting_update_gateway_config";
|
pub const VESTING_UPDATE_GATEWAY_CONFIG_EVENT_TYPE: &str = "vesting_update_gateway_config";
|
||||||
@@ -22,6 +23,7 @@ pub const VESTING_UPDATE_MIXNODE_COST_PARAMS_EVENT_TYPE: &str =
|
|||||||
"vesting_update_mixnode_cost_params";
|
"vesting_update_mixnode_cost_params";
|
||||||
|
|
||||||
pub const TRACK_MIXNODE_UNBOND_EVENT_TYPE: &str = "track_mixnode_unbond";
|
pub const TRACK_MIXNODE_UNBOND_EVENT_TYPE: &str = "track_mixnode_unbond";
|
||||||
|
pub const TRACK_MIXNODE_PLEDGE_DECREASE_EVENT_TYPE: &str = "track_mixnode_pledge_decrease";
|
||||||
pub const TRACK_GATEWAY_UNBOND_EVENT_TYPE: &str = "track_gateway_unbond";
|
pub const TRACK_GATEWAY_UNBOND_EVENT_TYPE: &str = "track_gateway_unbond";
|
||||||
pub const TRACK_UNDELEGATION_EVENT_TYPE: &str = "track_undelegation";
|
pub const TRACK_UNDELEGATION_EVENT_TYPE: &str = "track_undelegation";
|
||||||
pub const TRACK_REWARD_EVENT_TYPE: &str = "track_reaward";
|
pub const TRACK_REWARD_EVENT_TYPE: &str = "track_reaward";
|
||||||
@@ -118,6 +120,10 @@ pub fn new_vesting_pledge_more_event() -> Event {
|
|||||||
Event::new(VESTING_PLEDGE_MORE_EVENT_TYPE)
|
Event::new(VESTING_PLEDGE_MORE_EVENT_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_vesting_decrease_pledge_event() -> Event {
|
||||||
|
Event::new(VESTING_DECREASE_PLEDGE_EVENT_TYPE)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_vesting_update_mixnode_config_event() -> Event {
|
pub fn new_vesting_update_mixnode_config_event() -> Event {
|
||||||
Event::new(VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE)
|
Event::new(VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE)
|
||||||
}
|
}
|
||||||
@@ -146,6 +152,10 @@ pub fn new_track_mixnode_unbond_event() -> Event {
|
|||||||
Event::new(TRACK_MIXNODE_UNBOND_EVENT_TYPE)
|
Event::new(TRACK_MIXNODE_UNBOND_EVENT_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_track_mixnode_pledge_decrease_event() -> Event {
|
||||||
|
Event::new(TRACK_MIXNODE_PLEDGE_DECREASE_EVENT_TYPE)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_track_gateway_unbond_event() -> Event {
|
pub fn new_track_gateway_unbond_event() -> Event {
|
||||||
Event::new(TRACK_GATEWAY_UNBOND_EVENT_TYPE)
|
Event::new(TRACK_GATEWAY_UNBOND_EVENT_TYPE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,11 +123,18 @@ pub enum ExecuteMsg {
|
|||||||
PledgeMore {
|
PledgeMore {
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
},
|
},
|
||||||
|
DecreasePledge {
|
||||||
|
amount: Coin,
|
||||||
|
},
|
||||||
UnbondMixnode {},
|
UnbondMixnode {},
|
||||||
TrackUnbondMixnode {
|
TrackUnbondMixnode {
|
||||||
owner: String,
|
owner: String,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
},
|
},
|
||||||
|
TrackDecreasePledge {
|
||||||
|
owner: String,
|
||||||
|
amount: Coin,
|
||||||
|
},
|
||||||
BondGateway {
|
BondGateway {
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
owner_signature: MessageSignature,
|
owner_signature: MessageSignature,
|
||||||
@@ -175,8 +182,10 @@ impl ExecuteMsg {
|
|||||||
ExecuteMsg::TrackUndelegation { .. } => "VestingExecuteMsg::TrackUndelegation",
|
ExecuteMsg::TrackUndelegation { .. } => "VestingExecuteMsg::TrackUndelegation",
|
||||||
ExecuteMsg::BondMixnode { .. } => "VestingExecuteMsg::BondMixnode",
|
ExecuteMsg::BondMixnode { .. } => "VestingExecuteMsg::BondMixnode",
|
||||||
ExecuteMsg::PledgeMore { .. } => "VestingExecuteMsg::PledgeMore",
|
ExecuteMsg::PledgeMore { .. } => "VestingExecuteMsg::PledgeMore",
|
||||||
|
ExecuteMsg::DecreasePledge { .. } => "VestingExecuteMsg::DecreasePledge",
|
||||||
ExecuteMsg::UnbondMixnode { .. } => "VestingExecuteMsg::UnbondMixnode",
|
ExecuteMsg::UnbondMixnode { .. } => "VestingExecuteMsg::UnbondMixnode",
|
||||||
ExecuteMsg::TrackUnbondMixnode { .. } => "VestingExecuteMsg::TrackUnbondMixnode",
|
ExecuteMsg::TrackUnbondMixnode { .. } => "VestingExecuteMsg::TrackUnbondMixnode",
|
||||||
|
ExecuteMsg::TrackDecreasePledge { .. } => "VestingExecuteMsg::TrackDecreasePledge",
|
||||||
ExecuteMsg::BondGateway { .. } => "VestingExecuteMsg::BondGateway",
|
ExecuteMsg::BondGateway { .. } => "VestingExecuteMsg::BondGateway",
|
||||||
ExecuteMsg::UnbondGateway { .. } => "VestingExecuteMsg::UnbondGateway",
|
ExecuteMsg::UnbondGateway { .. } => "VestingExecuteMsg::UnbondGateway",
|
||||||
ExecuteMsg::TrackUnbondGateway { .. } => "VestingExecuteMsg::TrackUnbondGateway",
|
ExecuteMsg::TrackUnbondGateway { .. } => "VestingExecuteMsg::TrackUnbondGateway",
|
||||||
|
|||||||
@@ -9,9 +9,16 @@ edition = "2021"
|
|||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
|
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]}
|
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = { version = "1.24.1", features = [ "rt-multi-thread", "net", "signal", "fs" ] }
|
tokio = { version = "1.24.1", features = ["sync"]}
|
||||||
|
|
||||||
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||||
|
version = "0.5"
|
||||||
|
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
|
||||||
|
|
||||||
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
|
||||||
|
version = "1.24.1"
|
||||||
|
features = [ "rt-multi-thread", "net", "signal", "fs" ]
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::models::CoconutCredential;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CoconutCredentialManager {
|
||||||
|
inner: Arc<RwLock<Vec<CoconutCredential>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CoconutCredentialManager {
|
||||||
|
/// Creates new empty instance of the `CoconutCredentialManager`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
CoconutCredentialManager {
|
||||||
|
inner: Arc::new(RwLock::new(Vec::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts provided signature into the database.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `voucher_value`: Plaintext bandwidth value of the credential.
|
||||||
|
/// * `voucher_info`: Plaintext information of the credential.
|
||||||
|
/// * `serial_number`: Base58 representation of the serial number attribute.
|
||||||
|
/// * `binding_number`: Base58 representation of the binding number attribute.
|
||||||
|
/// * `signature`: Coconut credential in the form of a signature.
|
||||||
|
pub async fn insert_coconut_credential(
|
||||||
|
&self,
|
||||||
|
voucher_value: String,
|
||||||
|
voucher_info: String,
|
||||||
|
serial_number: String,
|
||||||
|
binding_number: String,
|
||||||
|
signature: String,
|
||||||
|
epoch_id: String,
|
||||||
|
) {
|
||||||
|
let mut creds = self.inner.write().await;
|
||||||
|
let id = creds.len() as i64;
|
||||||
|
creds.push(CoconutCredential {
|
||||||
|
id,
|
||||||
|
voucher_value,
|
||||||
|
voucher_info,
|
||||||
|
serial_number,
|
||||||
|
binding_number,
|
||||||
|
signature,
|
||||||
|
epoch_id,
|
||||||
|
consumed: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to retrieve one of the stored, unused credentials.
|
||||||
|
pub async fn get_next_coconut_credential(&self) -> Option<CoconutCredential> {
|
||||||
|
let creds = self.inner.read().await;
|
||||||
|
creds.iter().find(|c| !c.consumed).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes in the database the specified credential.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `id`: Database id.
|
||||||
|
pub async fn consume_coconut_credential(&self, id: i64) {
|
||||||
|
let mut creds = self.inner.write().await;
|
||||||
|
if let Some(cred) = creds.get_mut(id as usize) {
|
||||||
|
cred.consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
pub mod memory;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub mod sqlite;
|
||||||
+5
-5
@@ -4,7 +4,7 @@
|
|||||||
use crate::models::CoconutCredential;
|
use crate::models::CoconutCredential;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct CoconutCredentialManager {
|
pub struct CoconutCredentialManager {
|
||||||
connection_pool: sqlx::SqlitePool,
|
connection_pool: sqlx::SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ impl CoconutCredentialManager {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `connection_pool`: database connection pool to use.
|
/// * `connection_pool`: database connection pool to use.
|
||||||
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
pub fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
||||||
CoconutCredentialManager { connection_pool }
|
CoconutCredentialManager { connection_pool }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ impl CoconutCredentialManager {
|
|||||||
/// * `serial_number`: Base58 representation of the serial number attribute.
|
/// * `serial_number`: Base58 representation of the serial number attribute.
|
||||||
/// * `binding_number`: Base58 representation of the binding number attribute.
|
/// * `binding_number`: Base58 representation of the binding number attribute.
|
||||||
/// * `signature`: Coconut credential in the form of a signature.
|
/// * `signature`: Coconut credential in the form of a signature.
|
||||||
pub(crate) async fn insert_coconut_credential(
|
pub async fn insert_coconut_credential(
|
||||||
&self,
|
&self,
|
||||||
voucher_value: String,
|
voucher_value: String,
|
||||||
voucher_info: String,
|
voucher_info: String,
|
||||||
@@ -46,7 +46,7 @@ impl CoconutCredentialManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to retrieve one of the stored, unused credentials.
|
/// Tries to retrieve one of the stored, unused credentials.
|
||||||
pub(crate) async fn get_next_coconut_credential(
|
pub async fn get_next_coconut_credential(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Option<CoconutCredential>, sqlx::Error> {
|
) -> Result<Option<CoconutCredential>, sqlx::Error> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
@@ -62,7 +62,7 @@ impl CoconutCredentialManager {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `id`: Database id.
|
/// * `id`: Database id.
|
||||||
pub(crate) async fn consume_coconut_credential(&self, id: i64) -> Result<(), sqlx::Error> {
|
pub async fn consume_coconut_credential(&self, id: i64) -> Result<(), sqlx::Error> {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"UPDATE coconut_credentials SET consumed = TRUE WHERE id = ?",
|
"UPDATE coconut_credentials SET consumed = TRUE WHERE id = ?",
|
||||||
id
|
id
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::backends::memory::CoconutCredentialManager;
|
||||||
|
use crate::error::StorageError;
|
||||||
|
use crate::models::CoconutCredential;
|
||||||
|
use crate::storage::Storage;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
// note that clone here is fine as upon cloning the same underlying pool will be used
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct EphemeralStorage {
|
||||||
|
coconut_credential_manager: CoconutCredentialManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EphemeralStorage {
|
||||||
|
fn default() -> Self {
|
||||||
|
EphemeralStorage {
|
||||||
|
coconut_credential_manager: CoconutCredentialManager::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Storage for EphemeralStorage {
|
||||||
|
async fn insert_coconut_credential(
|
||||||
|
&self,
|
||||||
|
voucher_value: String,
|
||||||
|
voucher_info: String,
|
||||||
|
serial_number: String,
|
||||||
|
binding_number: String,
|
||||||
|
signature: String,
|
||||||
|
epoch_id: String,
|
||||||
|
) -> Result<(), StorageError> {
|
||||||
|
self.coconut_credential_manager
|
||||||
|
.insert_coconut_credential(
|
||||||
|
voucher_value,
|
||||||
|
voucher_info,
|
||||||
|
serial_number,
|
||||||
|
binding_number,
|
||||||
|
signature,
|
||||||
|
epoch_id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
|
||||||
|
let credential = self
|
||||||
|
.coconut_credential_manager
|
||||||
|
.get_next_coconut_credential()
|
||||||
|
.await
|
||||||
|
.ok_or(StorageError::NoCredential)?;
|
||||||
|
|
||||||
|
Ok(credential)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> {
|
||||||
|
self.coconut_credential_manager
|
||||||
|
.consume_coconut_credential(id)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::models::ERC20Credential;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(crate) struct ERC20CredentialManager {
|
|
||||||
connection_pool: sqlx::SqlitePool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ERC20CredentialManager {
|
|
||||||
/// Creates new instance of the `ERC20CredentialManager` with the provided sqlite connection pool.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `connection_pool`: database connection pool to use.
|
|
||||||
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
|
||||||
ERC20CredentialManager { connection_pool }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,11 @@ use thiserror::Error;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum StorageError {
|
pub enum StorageError {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[error("Database experienced an internal error - {0}")]
|
#[error("Database experienced an internal error - {0}")]
|
||||||
InternalDatabaseError(#[from] sqlx::Error),
|
InternalDatabaseError(#[from] sqlx::Error),
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[error("Failed to perform database migration - {0}")]
|
#[error("Failed to perform database migration - {0}")]
|
||||||
MigrationError(#[from] sqlx::migrate::MigrateError),
|
MigrationError(#[from] sqlx::migrate::MigrateError),
|
||||||
|
|
||||||
|
|||||||
@@ -3,111 +3,26 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::coconut::CoconutCredentialManager;
|
use crate::ephemeral_storage::EphemeralStorage;
|
||||||
use crate::error::StorageError;
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use crate::storage::Storage;
|
use crate::persistent_storage::PersistentStorage;
|
||||||
|
|
||||||
use crate::models::CoconutCredential;
|
mod backends;
|
||||||
use async_trait::async_trait;
|
pub mod ephemeral_storage;
|
||||||
use log::{debug, error};
|
|
||||||
use sqlx::ConnectOptions;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
mod coconut;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod models;
|
mod models;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub mod persistent_storage;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
|
||||||
// note that clone here is fine as upon cloning the same underlying pool will be used
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[derive(Clone)]
|
pub async fn initialise_persistent_storage(path: std::path::PathBuf) -> PersistentStorage {
|
||||||
pub struct PersistentStorage {
|
match persistent_storage::PersistentStorage::init(path).await {
|
||||||
coconut_credential_manager: CoconutCredentialManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PersistentStorage {
|
|
||||||
/// Initialises `PersistentStorage` using the provided path.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `database_path`: path to the database.
|
|
||||||
pub async fn init<P: AsRef<Path> + Send>(database_path: P) -> Result<Self, StorageError> {
|
|
||||||
debug!(
|
|
||||||
"Attempting to connect to database {:?}",
|
|
||||||
database_path.as_ref().as_os_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
|
|
||||||
.filename(database_path)
|
|
||||||
.create_if_missing(true);
|
|
||||||
|
|
||||||
opts.disable_statement_logging();
|
|
||||||
|
|
||||||
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
|
|
||||||
Ok(db) => db,
|
|
||||||
Err(err) => {
|
|
||||||
error!("Failed to connect to SQLx database: {err}");
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = sqlx::migrate!("./migrations").run(&connection_pool).await {
|
|
||||||
error!("Failed to perform migration on the SQLx database: {err}");
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(PersistentStorage {
|
|
||||||
coconut_credential_manager: CoconutCredentialManager::new(connection_pool.clone()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Storage for PersistentStorage {
|
|
||||||
async fn insert_coconut_credential(
|
|
||||||
&self,
|
|
||||||
voucher_value: String,
|
|
||||||
voucher_info: String,
|
|
||||||
serial_number: String,
|
|
||||||
binding_number: String,
|
|
||||||
signature: String,
|
|
||||||
epoch_id: String,
|
|
||||||
) -> Result<(), StorageError> {
|
|
||||||
self.coconut_credential_manager
|
|
||||||
.insert_coconut_credential(
|
|
||||||
voucher_value,
|
|
||||||
voucher_info,
|
|
||||||
serial_number,
|
|
||||||
binding_number,
|
|
||||||
signature,
|
|
||||||
epoch_id,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
|
|
||||||
let credential = self
|
|
||||||
.coconut_credential_manager
|
|
||||||
.get_next_coconut_credential()
|
|
||||||
.await?
|
|
||||||
.ok_or(StorageError::NoCredential)?;
|
|
||||||
|
|
||||||
Ok(credential)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> {
|
|
||||||
self.coconut_credential_manager
|
|
||||||
.consume_coconut_credential(id)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn initialise_storage(path: PathBuf) -> PersistentStorage {
|
|
||||||
match PersistentStorage::init(path).await {
|
|
||||||
Err(err) => panic!("failed to initialise credential storage - {err}"),
|
Err(err) => panic!("failed to initialise credential storage - {err}"),
|
||||||
Ok(storage) => storage,
|
Ok(storage) => storage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initialise_ephemeral_storage() -> EphemeralStorage {
|
||||||
|
ephemeral_storage::EphemeralStorage::default()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct CoconutCredential {
|
pub struct CoconutCredential {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::backends::sqlite::CoconutCredentialManager;
|
||||||
|
use crate::error::StorageError;
|
||||||
|
use crate::storage::Storage;
|
||||||
|
|
||||||
|
use crate::models::CoconutCredential;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use log::{debug, error};
|
||||||
|
use sqlx::ConnectOptions;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
// note that clone here is fine as upon cloning the same underlying pool will be used
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PersistentStorage {
|
||||||
|
coconut_credential_manager: CoconutCredentialManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PersistentStorage {
|
||||||
|
/// Initialises `PersistentStorage` using the provided path.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `database_path`: path to the database.
|
||||||
|
pub async fn init<P: AsRef<Path> + Send>(database_path: P) -> Result<Self, StorageError> {
|
||||||
|
debug!(
|
||||||
|
"Attempting to connect to database {:?}",
|
||||||
|
database_path.as_ref().as_os_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||||
|
.filename(database_path)
|
||||||
|
.create_if_missing(true);
|
||||||
|
|
||||||
|
opts.disable_statement_logging();
|
||||||
|
|
||||||
|
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
|
||||||
|
Ok(db) => db,
|
||||||
|
Err(err) => {
|
||||||
|
error!("Failed to connect to SQLx database: {err}");
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = sqlx::migrate!("./migrations").run(&connection_pool).await {
|
||||||
|
error!("Failed to perform migration on the SQLx database: {err}");
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PersistentStorage {
|
||||||
|
coconut_credential_manager: CoconutCredentialManager::new(connection_pool.clone()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Storage for PersistentStorage {
|
||||||
|
async fn insert_coconut_credential(
|
||||||
|
&self,
|
||||||
|
voucher_value: String,
|
||||||
|
voucher_info: String,
|
||||||
|
serial_number: String,
|
||||||
|
binding_number: String,
|
||||||
|
signature: String,
|
||||||
|
epoch_id: String,
|
||||||
|
) -> Result<(), StorageError> {
|
||||||
|
self.coconut_credential_manager
|
||||||
|
.insert_coconut_credential(
|
||||||
|
voucher_value,
|
||||||
|
voucher_info,
|
||||||
|
serial_number,
|
||||||
|
binding_number,
|
||||||
|
signature,
|
||||||
|
epoch_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
|
||||||
|
let credential = self
|
||||||
|
.coconut_credential_manager
|
||||||
|
.get_next_coconut_credential()
|
||||||
|
.await?
|
||||||
|
.ok_or(StorageError::NoCredential)?;
|
||||||
|
|
||||||
|
Ok(credential)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> {
|
||||||
|
self.coconut_credential_manager
|
||||||
|
.consume_coconut_credential(id)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::error::StorageError;
|
||||||
use crate::models::CoconutCredential;
|
use crate::models::CoconutCredential;
|
||||||
use crate::StorageError;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Storage: Send + Sync {
|
pub trait Storage: Send + Sync {
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum StorageError {
|
|
||||||
#[error("Android is not yet supported")]
|
|
||||||
AndroidNotSupported,
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[error("Code shouldn't reach this point")]
|
|
||||||
InconsistentData,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PersistentStorage {}
|
|
||||||
|
|
||||||
pub struct CoconutCredential {
|
|
||||||
pub id: i64,
|
|
||||||
pub voucher_value: String,
|
|
||||||
pub voucher_info: String,
|
|
||||||
pub serial_number: String,
|
|
||||||
pub binding_number: String,
|
|
||||||
pub signature: String,
|
|
||||||
pub epoch_id: String,
|
|
||||||
pub consumed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Storage: Send + Sync {
|
|
||||||
async fn insert_coconut_credential(
|
|
||||||
&self,
|
|
||||||
voucher_value: String,
|
|
||||||
voucher_info: String,
|
|
||||||
serial_number: String,
|
|
||||||
binding_number: String,
|
|
||||||
signature: String,
|
|
||||||
) -> Result<(), StorageError>;
|
|
||||||
|
|
||||||
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError>;
|
|
||||||
|
|
||||||
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Storage for PersistentStorage {
|
|
||||||
async fn insert_coconut_credential(
|
|
||||||
&self,
|
|
||||||
_voucher_value: String,
|
|
||||||
_voucher_info: String,
|
|
||||||
_serial_number: String,
|
|
||||||
_binding_number: String,
|
|
||||||
_signature: String,
|
|
||||||
) -> Result<(), StorageError> {
|
|
||||||
Err(StorageError::AndroidNotSupported)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
|
|
||||||
Err(StorageError::AndroidNotSupported)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn consume_coconut_credential(&self, _id: i64) -> Result<(), StorageError> {
|
|
||||||
Err(StorageError::AndroidNotSupported)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,17 +19,6 @@ pub struct ChainDetails {
|
|||||||
pub stake_denom: DenomDetailsOwned,
|
pub stake_denom: DenomDetailsOwned,
|
||||||
}
|
}
|
||||||
|
|
||||||
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
|
|
||||||
impl Default for ChainDetails {
|
|
||||||
fn default() -> Self {
|
|
||||||
ChainDetails {
|
|
||||||
bech32_account_prefix: mainnet::BECH32_PREFIX.into(),
|
|
||||||
mix_denom: mainnet::MIX_DENOM.into(),
|
|
||||||
stake_denom: mainnet::STAKE_DENOM.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct NymContracts {
|
pub struct NymContracts {
|
||||||
pub mixnet_contract_address: Option<String>,
|
pub mixnet_contract_address: Option<String>,
|
||||||
@@ -43,20 +32,43 @@ pub struct NymContracts {
|
|||||||
|
|
||||||
// I wanted to use the simpler `NetworkDetails` name, but there's a clash
|
// I wanted to use the simpler `NetworkDetails` name, but there's a clash
|
||||||
// with `NetworkDetails` defined in all.rs...
|
// with `NetworkDetails` defined in all.rs...
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct NymNetworkDetails {
|
pub struct NymNetworkDetails {
|
||||||
pub chain_details: ChainDetails,
|
pub chain_details: ChainDetails,
|
||||||
pub endpoints: Vec<ValidatorDetails>,
|
pub endpoints: Vec<ValidatorDetails>,
|
||||||
pub contracts: NymContracts,
|
pub contracts: NymContracts,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
|
||||||
|
impl Default for NymNetworkDetails {
|
||||||
|
fn default() -> Self {
|
||||||
|
NymNetworkDetails::new_mainnet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NymNetworkDetails {
|
impl NymNetworkDetails {
|
||||||
pub fn new() -> Self {
|
pub fn new_empty() -> Self {
|
||||||
NymNetworkDetails::default()
|
NymNetworkDetails {
|
||||||
|
chain_details: ChainDetails {
|
||||||
|
bech32_account_prefix: Default::default(),
|
||||||
|
mix_denom: DenomDetailsOwned {
|
||||||
|
base: Default::default(),
|
||||||
|
display: Default::default(),
|
||||||
|
display_exponent: Default::default(),
|
||||||
|
},
|
||||||
|
stake_denom: DenomDetailsOwned {
|
||||||
|
base: Default::default(),
|
||||||
|
display: Default::default(),
|
||||||
|
display_exponent: Default::default(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
endpoints: Default::default(),
|
||||||
|
contracts: Default::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_env() -> Self {
|
pub fn new_from_env() -> Self {
|
||||||
NymNetworkDetails::new()
|
NymNetworkDetails::new_empty()
|
||||||
.with_bech32_account_prefix(
|
.with_bech32_account_prefix(
|
||||||
var(var_names::BECH32_PREFIX).expect("bech32 prefix not set"),
|
var(var_names::BECH32_PREFIX).expect("bech32 prefix not set"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ repository = { workspace = true }
|
|||||||
nym-sphinx-addressing = { path = "../addressing" }
|
nym-sphinx-addressing = { path = "../addressing" }
|
||||||
nym-sphinx-params = { path = "../params" }
|
nym-sphinx-params = { path = "../params" }
|
||||||
nym-sphinx-types = { path = "../types" }
|
nym-sphinx-types = { path = "../types" }
|
||||||
|
nym-outfox = { path = "../../../nym-outfox" }
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
|||||||
|
|
||||||
nym-client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
nym-client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||||
nym-config = { path = "../config" }
|
nym-config = { path = "../config" }
|
||||||
nym-credential-storage = { path = "../credential-storage", optional = true }
|
nym-credential-storage = { path = "../credential-storage" }
|
||||||
nym-network-defaults = { path = "../network-defaults" }
|
nym-network-defaults = { path = "../network-defaults" }
|
||||||
nym-socks5-proxy-helpers = { path = "../socks5/proxy-helpers" }
|
nym-socks5-proxy-helpers = { path = "../socks5/proxy-helpers" }
|
||||||
nym-service-providers-common = { path = "../../service-providers/common" }
|
nym-service-providers-common = { path = "../../service-providers/common" }
|
||||||
@@ -29,4 +29,4 @@ nym-task = { path = "../task" }
|
|||||||
nym-validator-client = { path = "../client-libs/validator-client", features = ["nyxd-client"] }
|
nym-validator-client = { path = "../client-libs/validator-client", features = ["nyxd-client"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["nym-credential-storage"]
|
default = []
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use crate::socks::{
|
|||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use nym_client_core::client::base_client::helpers::setup_empty_reply_surb_backend;
|
use nym_client_core::client::base_client::helpers::setup_empty_reply_surb_backend;
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
@@ -20,8 +21,7 @@ use nym_client_core::client::base_client::{
|
|||||||
};
|
};
|
||||||
use nym_client_core::client::key_manager::KeyManager;
|
use nym_client_core::client::key_manager::KeyManager;
|
||||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
#[cfg(not(target_os = "android"))]
|
use nym_credential_storage::storage::Storage;
|
||||||
use nym_gateway_client::bandwidth::BandwidthController;
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_task::{TaskClient, TaskManager};
|
use nym_task::{TaskClient, TaskManager};
|
||||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||||
@@ -74,10 +74,10 @@ impl NymClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
async fn create_bandwidth_controller<St: Storage>(
|
||||||
async fn create_bandwidth_controller(
|
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> BandwidthController<Client<QueryNyxdClient>> {
|
storage: St,
|
||||||
|
) -> BandwidthController<Client<QueryNyxdClient>, St> {
|
||||||
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
|
||||||
let mut client_config =
|
let mut client_config =
|
||||||
nym_validator_client::Config::try_from_nym_network_details(&details)
|
nym_validator_client::Config::try_from_nym_network_details(&details)
|
||||||
@@ -97,13 +97,6 @@ impl NymClient {
|
|||||||
let client = nym_validator_client::Client::new_query(client_config)
|
let client = nym_validator_client::Client::new_query(client_config)
|
||||||
.expect("Could not construct query client");
|
.expect("Could not construct query client");
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
let storage =
|
|
||||||
nym_credential_storage::initialise_storage(config.get_base().get_database_path()).await;
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
let storage = mobile_storage::PersistentStorage {};
|
|
||||||
|
|
||||||
BandwidthController::new(storage, client)
|
BandwidthController::new(storage, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +216,16 @@ impl NymClient {
|
|||||||
let base_builder = BaseClientBuilder::new_from_base_config(
|
let base_builder = BaseClientBuilder::new_from_base_config(
|
||||||
self.config.get_base(),
|
self.config.get_base(),
|
||||||
self.key_manager,
|
self.key_manager,
|
||||||
Some(Self::create_bandwidth_controller(&self.config).await),
|
Some(
|
||||||
|
Self::create_bandwidth_controller(
|
||||||
|
&self.config,
|
||||||
|
nym_credential_storage::initialise_persistent_storage(
|
||||||
|
self.config.get_base().get_database_path(),
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
non_wasm_helpers::setup_fs_reply_surb_backend(
|
non_wasm_helpers::setup_fs_reply_surb_backend(
|
||||||
Some(self.config.get_base().get_reply_surb_database_path()),
|
Some(self.config.get_base().get_reply_surb_database_path()),
|
||||||
self.config.get_debug_settings(),
|
self.config.get_debug_settings(),
|
||||||
@@ -232,10 +234,16 @@ impl NymClient {
|
|||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
let base_builder = BaseClientBuilder::<_, Client<QueryNyxdClient>>::new_from_base_config(
|
let base_builder = BaseClientBuilder::<_, Client<QueryNyxdClient>, _>::new_from_base_config(
|
||||||
self.config.get_base(),
|
self.config.get_base(),
|
||||||
self.key_manager,
|
self.key_manager,
|
||||||
None,
|
Some(
|
||||||
|
Self::create_bandwidth_controller(
|
||||||
|
&self.config,
|
||||||
|
nym_credential_storage::initialise_ephemeral_storage(),
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
setup_empty_reply_surb_backend(self.config.get_debug_settings()),
|
setup_empty_reply_surb_backend(self.config.get_debug_settings()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ pub enum PendingEpochEventData {
|
|||||||
mix_id: MixId,
|
mix_id: MixId,
|
||||||
amount: DecCoin,
|
amount: DecCoin,
|
||||||
},
|
},
|
||||||
|
DecreasePledge {
|
||||||
|
mix_id: MixId,
|
||||||
|
decrease_by: DecCoin,
|
||||||
|
},
|
||||||
UnbondMixnode {
|
UnbondMixnode {
|
||||||
mix_id: MixId,
|
mix_id: MixId,
|
||||||
},
|
},
|
||||||
@@ -101,6 +105,13 @@ impl PendingEpochEventData {
|
|||||||
amount: reg.attempt_convert_to_display_dec_coin(amount.into())?,
|
amount: reg.attempt_convert_to_display_dec_coin(amount.into())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
MixnetContractPendingEpochEventKind::DecreasePledge {
|
||||||
|
mix_id,
|
||||||
|
decrease_by,
|
||||||
|
} => Ok(PendingEpochEventData::DecreasePledge {
|
||||||
|
mix_id,
|
||||||
|
decrease_by: reg.attempt_convert_to_display_dec_coin(decrease_by.into())?,
|
||||||
|
}),
|
||||||
MixnetContractPendingEpochEventKind::UnbondMixnode { mix_id } => {
|
MixnetContractPendingEpochEventKind::UnbondMixnode { mix_id } => {
|
||||||
Ok(PendingEpochEventData::UnbondMixnode { mix_id })
|
Ok(PendingEpochEventData::UnbondMixnode { mix_id })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[alias]
|
||||||
|
wasm = "build --target wasm32-unknown-unknown"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
rustflags = ["-C", "link-arg=-s"]
|
||||||
|
#target = "wasm32-unknown-unknown"
|
||||||
Generated
+16
@@ -949,6 +949,22 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mixnet-vesting-integration-tests"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cosmwasm-storage",
|
||||||
|
"cw-multi-test",
|
||||||
|
"nym-contracts-common",
|
||||||
|
"nym-crypto",
|
||||||
|
"nym-mixnet-contract",
|
||||||
|
"nym-mixnet-contract-common",
|
||||||
|
"nym-vesting-contract",
|
||||||
|
"nym-vesting-contract-common",
|
||||||
|
"rand_chacha 0.2.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ members = [
|
|||||||
"coconut-dkg",
|
"coconut-dkg",
|
||||||
"coconut-test",
|
"coconut-test",
|
||||||
"mixnet",
|
"mixnet",
|
||||||
|
"mixnet-vesting-integration-tests",
|
||||||
"multisig/cw3-flex-multisig",
|
"multisig/cw3-flex-multisig",
|
||||||
"multisig/cw4-group",
|
"multisig/cw4-group",
|
||||||
"service-provider-directory",
|
"service-provider-directory",
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ mod tests {
|
|||||||
assert!(res.is_none());
|
assert!(res.is_none());
|
||||||
|
|
||||||
let mut spend_credential = SpendCredential::new(
|
let mut spend_credential = SpendCredential::new(
|
||||||
funds.clone(),
|
funds,
|
||||||
blind_serial_number.to_string(),
|
blind_serial_number.to_string(),
|
||||||
gateway_cosmos_address.clone(),
|
gateway_cosmos_address,
|
||||||
);
|
);
|
||||||
spend_credential.mark_as_spent();
|
spend_credential.mark_as_spent();
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>>
|
|||||||
};
|
};
|
||||||
let env = mock_env();
|
let env = mock_env();
|
||||||
let info = mock_info("creator", &[]);
|
let info = mock_info("creator", &[]);
|
||||||
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
|
instantiate(deps.as_mut(), env, info, msg).unwrap();
|
||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
let info = mock_info("requester", &[coin]);
|
let info = mock_info("requester", &[coin]);
|
||||||
|
|
||||||
let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap();
|
let tx = deposit_funds(deps.as_mut(), env, info, data).unwrap();
|
||||||
|
|
||||||
let events: Vec<_> = tx
|
let events: Vec<_> = tx
|
||||||
.events
|
.events
|
||||||
@@ -246,13 +246,8 @@ mod tests {
|
|||||||
|
|
||||||
deps.querier
|
deps.querier
|
||||||
.update_balance(env.contract.address.clone(), vec![funds.clone()]);
|
.update_balance(env.contract.address.clone(), vec![funds.clone()]);
|
||||||
let err = release_funds(
|
let err =
|
||||||
deps.as_mut(),
|
release_funds(deps.as_mut(), env, mock_info(invalid_admin, &[]), funds).unwrap_err();
|
||||||
env.clone(),
|
|
||||||
mock_info(invalid_admin, &[]),
|
|
||||||
funds.clone(),
|
|
||||||
)
|
|
||||||
.unwrap_err();
|
|
||||||
assert_eq!(err, ContractError::Admin(AdminError::NotAdmin {}));
|
assert_eq!(err, ContractError::Admin(AdminError::NotAdmin {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +289,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
assert_eq!(contract_addr, MULTISIG_CONTRACT);
|
assert_eq!(contract_addr, MULTISIG_CONTRACT);
|
||||||
assert!(funds.is_empty());
|
assert!(funds.is_empty());
|
||||||
let multisig_msg: MultisigExecuteMsg = from_binary(&msg).unwrap();
|
let multisig_msg: MultisigExecuteMsg = from_binary(msg).unwrap();
|
||||||
if let MultisigExecuteMsg::Propose {
|
if let MultisigExecuteMsg::Propose {
|
||||||
title: _,
|
title: _,
|
||||||
description,
|
description,
|
||||||
@@ -312,7 +307,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
assert_eq!(*contract_addr, env.contract.address.into_string());
|
assert_eq!(*contract_addr, env.contract.address.into_string());
|
||||||
assert!(funds.is_empty());
|
assert!(funds.is_empty());
|
||||||
let release_funds_req: ExecuteMsg = from_binary(&msg).unwrap();
|
let release_funds_req: ExecuteMsg = from_binary(msg).unwrap();
|
||||||
if let ExecuteMsg::ReleaseFunds { funds } = release_funds_req {
|
if let ExecuteMsg::ReleaseFunds { funds } = release_funds_req {
|
||||||
assert_eq!(funds, *data.funds());
|
assert_eq!(funds, *data.funds());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let info = mock_info("creator", &[]);
|
let info = mock_info("creator", &[]);
|
||||||
|
|
||||||
let res = instantiate(deps.as_mut(), env.clone(), info, msg);
|
let res = instantiate(deps.as_mut(), env, info, msg);
|
||||||
assert!(res.is_ok())
|
assert!(res.is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ mod tests {
|
|||||||
announce_address: "127.0.0.1:8000".to_string(),
|
announce_address: "127.0.0.1:8000".to_string(),
|
||||||
resharing: false,
|
resharing: false,
|
||||||
},
|
},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(parse_node_index(res), (idx + 1) as u64);
|
assert_eq!(parse_node_index(res), (idx + 1) as u64);
|
||||||
@@ -259,7 +259,7 @@ mod tests {
|
|||||||
announce_address: "127.0.0.1:8000".to_string(),
|
announce_address: "127.0.0.1:8000".to_string(),
|
||||||
resharing: false,
|
resharing: false,
|
||||||
},
|
},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(ContractError::AlreadyADealer, err.downcast().unwrap());
|
assert_eq!(ContractError::AlreadyADealer, err.downcast().unwrap());
|
||||||
@@ -269,13 +269,13 @@ mod tests {
|
|||||||
let err = app
|
let err = app
|
||||||
.execute_contract(
|
.execute_contract(
|
||||||
unauthorized_member,
|
unauthorized_member,
|
||||||
coconut_dkg_contract_addr.clone(),
|
coconut_dkg_contract_addr,
|
||||||
&RegisterDealer {
|
&RegisterDealer {
|
||||||
bte_key_with_proof: "bte_key_with_proof".to_string(),
|
bte_key_with_proof: "bte_key_with_proof".to_string(),
|
||||||
announce_address: "127.0.0.1:8000".to_string(),
|
announce_address: "127.0.0.1:8000".to_string(),
|
||||||
resharing: false,
|
resharing: false,
|
||||||
},
|
},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(ContractError::Unauthorized, err.downcast().unwrap());
|
assert_eq!(ContractError::Unauthorized, err.downcast().unwrap());
|
||||||
|
|||||||
@@ -153,9 +153,9 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
let ret = try_add_dealer(
|
let ret = try_add_dealer(
|
||||||
deps.as_mut(),
|
deps.as_mut(),
|
||||||
info.clone(),
|
info,
|
||||||
bte_key_with_proof.clone(),
|
bte_key_with_proof,
|
||||||
announce_address.clone(),
|
announce_address,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ pub(crate) mod tests {
|
|||||||
for n in 0..size {
|
for n in 0..size {
|
||||||
let dealing_share = dealing_bytes_fixture();
|
let dealing_share = dealing_bytes_fixture();
|
||||||
let sender = Addr::unchecked(format!("owner{}", n));
|
let sender = Addr::unchecked(format!("owner{}", n));
|
||||||
for idx in 0..TOTAL_DEALINGS {
|
(0..TOTAL_DEALINGS).for_each(|idx| {
|
||||||
DEALINGS_BYTES[idx]
|
DEALINGS_BYTES[idx]
|
||||||
.save(deps.storage, &sender, &dealing_share)
|
.save(deps.storage, &sender, &dealing_share)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ pub(crate) mod tests {
|
|||||||
assert!(ret.is_ok());
|
assert!(ret.is_ok());
|
||||||
assert!(dealings.has(deps.as_mut().storage, &owner));
|
assert!(dealings.has(deps.as_mut().storage, &owner));
|
||||||
}
|
}
|
||||||
let ret = try_commit_dealings(deps.as_mut(), info.clone(), dealing_bytes.clone(), true)
|
let ret = try_commit_dealings(deps.as_mut(), info, dealing_bytes, true).unwrap_err();
|
||||||
.unwrap_err();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ret,
|
ret,
|
||||||
ContractError::AlreadyCommitted {
|
ContractError::AlreadyCommitted {
|
||||||
|
|||||||
@@ -236,10 +236,10 @@ pub(crate) mod tests {
|
|||||||
let limit = *limits.next().unwrap();
|
let limit = *limits.next().unwrap();
|
||||||
{
|
{
|
||||||
let mut group_members = GROUP_MEMBERS.lock().unwrap();
|
let mut group_members = GROUP_MEMBERS.lock().unwrap();
|
||||||
for i in 0..n as usize {
|
for dealer in dealers.iter() {
|
||||||
group_members.push((
|
group_members.push((
|
||||||
Member {
|
Member {
|
||||||
addr: dealers[i].address.to_string(),
|
addr: dealer.address.to_string(),
|
||||||
weight: 10,
|
weight: 10,
|
||||||
},
|
},
|
||||||
1,
|
1,
|
||||||
@@ -339,7 +339,7 @@ pub(crate) mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
for i in 0..3 as u64 {
|
for i in 0..3_u64 {
|
||||||
let details = dealer_details_fixture(i + 1);
|
let details = dealer_details_fixture(i + 1);
|
||||||
current_dealers()
|
current_dealers()
|
||||||
.save(deps.as_mut().storage, &details.address, &details)
|
.save(deps.as_mut().storage, &details.address, &details)
|
||||||
|
|||||||
@@ -90,6 +90,6 @@ pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>>
|
|||||||
};
|
};
|
||||||
let env = mock_env();
|
let env = mock_env();
|
||||||
let info = mock_info(ADMIN_ADDRESS, &[]);
|
let info = mock_info(ADMIN_ADDRESS, &[]);
|
||||||
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
|
instantiate(deps.as_mut(), env, info, msg).unwrap();
|
||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,14 +129,8 @@ mod tests {
|
|||||||
.save(deps.as_mut().storage, &dealer, &dealer_details)
|
.save(deps.as_mut().storage, &dealer, &dealer_details)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
try_commit_verification_key_share(
|
try_commit_verification_key_share(deps.as_mut(), env, info.clone(), share.clone(), false)
|
||||||
deps.as_mut(),
|
.unwrap();
|
||||||
env.clone(),
|
|
||||||
info.clone(),
|
|
||||||
share.clone(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let vk_share = vk_shares().load(&deps.storage, (&info.sender, 0)).unwrap();
|
let vk_share = vk_shares().load(&deps.storage, (&info.sender, 0)).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vk_share,
|
vk_share,
|
||||||
@@ -215,14 +209,8 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let ret = try_commit_verification_key_share(
|
let ret =
|
||||||
deps.as_mut(),
|
try_commit_verification_key_share(deps.as_mut(), env, info, share, false).unwrap_err();
|
||||||
env.clone(),
|
|
||||||
info.clone(),
|
|
||||||
share.clone(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap_err();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ret,
|
ret,
|
||||||
ContractError::AlreadyCommitted {
|
ContractError::AlreadyCommitted {
|
||||||
@@ -318,14 +306,7 @@ mod tests {
|
|||||||
dealers_storage::current_dealers()
|
dealers_storage::current_dealers()
|
||||||
.save(deps.as_mut().storage, &owner, &dealer_details)
|
.save(deps.as_mut().storage, &owner, &dealer_details)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
try_commit_verification_key_share(
|
try_commit_verification_key_share(deps.as_mut(), env.clone(), info, share, false).unwrap();
|
||||||
deps.as_mut(),
|
|
||||||
env.clone(),
|
|
||||||
info.clone(),
|
|
||||||
share.clone(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
env.block.time = env
|
env.block.time = env
|
||||||
.block
|
.block
|
||||||
@@ -338,7 +319,6 @@ mod tests {
|
|||||||
.plus_seconds(TimeConfiguration::default().verification_key_validation_time_secs);
|
.plus_seconds(TimeConfiguration::default().verification_key_validation_time_secs);
|
||||||
advance_epoch_state(deps.as_mut(), env).unwrap();
|
advance_epoch_state(deps.as_mut(), env).unwrap();
|
||||||
|
|
||||||
try_verify_verification_key_share(deps.as_mut(), multisig_info, owner.clone(), false)
|
try_verify_verification_key_share(deps.as_mut(), multisig_info, owner, false).unwrap();
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,13 +89,8 @@ fn deposit_and_release() {
|
|||||||
let msg = ExecuteMsg::ReleaseFunds {
|
let msg = ExecuteMsg::ReleaseFunds {
|
||||||
funds: deposit_funds[0].clone(),
|
funds: deposit_funds[0].clone(),
|
||||||
};
|
};
|
||||||
app.execute_contract(
|
app.execute_contract(Addr::unchecked(multisig_addr), contract_addr, &msg, &[])
|
||||||
Addr::unchecked(multisig_addr),
|
.unwrap();
|
||||||
contract_addr.clone(),
|
|
||||||
&msg,
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let pool_bal = app.wrap().query_balance(pool_addr, TEST_MIX_DENOM).unwrap();
|
let pool_bal = app.wrap().query_balance(pool_addr, TEST_MIX_DENOM).unwrap();
|
||||||
assert_eq!(pool_bal, deposit_funds[0]);
|
assert_eq!(pool_bal, deposit_funds[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ fn spend_credential_creates_proposal() {
|
|||||||
Addr::unchecked(OWNER),
|
Addr::unchecked(OWNER),
|
||||||
coconut_bandwidth_contract_addr.clone(),
|
coconut_bandwidth_contract_addr.clone(),
|
||||||
&msg,
|
&msg,
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let proposal_id = res
|
let proposal_id = res
|
||||||
@@ -124,7 +124,7 @@ fn spend_credential_creates_proposal() {
|
|||||||
Addr::unchecked(OWNER),
|
Addr::unchecked(OWNER),
|
||||||
coconut_bandwidth_contract_addr.clone(),
|
coconut_bandwidth_contract_addr.clone(),
|
||||||
&msg,
|
&msg,
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -142,9 +142,9 @@ fn spend_credential_creates_proposal() {
|
|||||||
let res = app
|
let res = app
|
||||||
.execute_contract(
|
.execute_contract(
|
||||||
Addr::unchecked(OWNER),
|
Addr::unchecked(OWNER),
|
||||||
coconut_bandwidth_contract_addr.clone(),
|
coconut_bandwidth_contract_addr,
|
||||||
&msg,
|
&msg,
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let proposal_id = res
|
let proposal_id = res
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ fn dkg_proposal() {
|
|||||||
announce_address: "127.0.0.1:8000".to_string(),
|
announce_address: "127.0.0.1:8000".to_string(),
|
||||||
resharing: false,
|
resharing: false,
|
||||||
},
|
},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ fn dkg_proposal() {
|
|||||||
Addr::unchecked(OWNER),
|
Addr::unchecked(OWNER),
|
||||||
coconut_dkg_contract_addr.clone(),
|
coconut_dkg_contract_addr.clone(),
|
||||||
&AdvanceEpochState {},
|
&AdvanceEpochState {},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ fn dkg_proposal() {
|
|||||||
Addr::unchecked(MEMBER1),
|
Addr::unchecked(MEMBER1),
|
||||||
coconut_dkg_contract_addr.clone(),
|
coconut_dkg_contract_addr.clone(),
|
||||||
&msg,
|
&msg,
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ fn dkg_proposal() {
|
|||||||
proposal_id,
|
proposal_id,
|
||||||
vote: cw3::Vote::Yes,
|
vote: cw3::Vote::Yes,
|
||||||
},
|
},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -184,16 +184,16 @@ fn dkg_proposal() {
|
|||||||
Addr::unchecked(OWNER),
|
Addr::unchecked(OWNER),
|
||||||
coconut_dkg_contract_addr.clone(),
|
coconut_dkg_contract_addr.clone(),
|
||||||
&AdvanceEpochState {},
|
&AdvanceEpochState {},
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.execute_contract(
|
app.execute_contract(
|
||||||
Addr::unchecked(MEMBER1),
|
Addr::unchecked(MEMBER1),
|
||||||
multisig_contract_addr.clone(),
|
multisig_contract_addr,
|
||||||
&Execute { proposal_id },
|
&Execute { proposal_id },
|
||||||
&vec![],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "mixnet-vesting-integration-tests"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
# cosmwasm dependencies
|
||||||
|
cosmwasm-std = { workspace = true }
|
||||||
|
cosmwasm-storage = { workspace = true }
|
||||||
|
cw-multi-test = { workspace = true }
|
||||||
|
|
||||||
|
# contracts dependencies
|
||||||
|
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||||
|
nym-vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||||
|
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" }
|
||||||
|
|
||||||
|
nym-mixnet-contract = { path = "../mixnet" }
|
||||||
|
nym-vesting-contract = { path = "../vesting" }
|
||||||
|
|
||||||
|
# other local dependencies
|
||||||
|
nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
|
||||||
|
|
||||||
|
# external dependencies
|
||||||
|
rand_chacha = "0.2"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "mixnet-vesting-test"
|
||||||
|
path = "src/tests.rs"
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::support::helpers::{mix_coin, mix_coins, vesting_owner};
|
||||||
|
use crate::support::setup::{TestSetup, MIX_DENOM};
|
||||||
|
use cosmwasm_std::Addr;
|
||||||
|
use cw_multi_test::Executor;
|
||||||
|
use nym_contracts_common::Percent;
|
||||||
|
use nym_mixnet_contract_common::error::MixnetContractError;
|
||||||
|
use nym_mixnet_contract_common::{ContractStateParams, MixNodeCostParams};
|
||||||
|
use nym_mixnet_contract_common::{MixOwnershipResponse, QueryMsg as MixnetQueryMsg};
|
||||||
|
use nym_vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
|
||||||
|
use vesting_contract::errors::ContractError as VestingContractError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decrease_mixnode_pledge_from_vesting_account_with_minimum_pledge() {
|
||||||
|
let mut test = TestSetup::new_simple();
|
||||||
|
let vesting_account = "vesting-account";
|
||||||
|
|
||||||
|
// 0. get the minimum pledge amount
|
||||||
|
let state_params: ContractStateParams = test
|
||||||
|
.app
|
||||||
|
.wrap()
|
||||||
|
.query_wasm_smart(test.mixnet_contract(), &MixnetQueryMsg::GetStateParams {})
|
||||||
|
.unwrap();
|
||||||
|
let minimum_pledge = state_params.minimum_mixnode_pledge;
|
||||||
|
|
||||||
|
// 1. create vesting account
|
||||||
|
let create_msg = VestingExecuteMsg::CreateAccount {
|
||||||
|
owner_address: vesting_account.to_string(),
|
||||||
|
staking_address: None,
|
||||||
|
vesting_spec: None,
|
||||||
|
cap: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
test.app
|
||||||
|
.execute_contract(
|
||||||
|
vesting_owner(),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&create_msg,
|
||||||
|
&mix_coins(1_000_000_000),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// 2. bond mixnode with the vesting account
|
||||||
|
let pledge = minimum_pledge.clone();
|
||||||
|
|
||||||
|
let cost_params = MixNodeCostParams {
|
||||||
|
profit_margin_percent: Percent::from_percentage_value(10).unwrap(),
|
||||||
|
interval_operating_cost: mix_coin(40_000_000),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (mix_node, owner_signature) = test.valid_mixnode_with_sig(
|
||||||
|
vesting_account,
|
||||||
|
Some(test.vesting_contract()),
|
||||||
|
cost_params.clone(),
|
||||||
|
pledge.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let bond_msg = VestingExecuteMsg::BondMixnode {
|
||||||
|
mix_node,
|
||||||
|
cost_params,
|
||||||
|
owner_signature,
|
||||||
|
amount: pledge.clone(),
|
||||||
|
};
|
||||||
|
test.app
|
||||||
|
.execute_contract(
|
||||||
|
Addr::unchecked(vesting_account),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&bond_msg,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// 3. try to decrease the pledge
|
||||||
|
|
||||||
|
// trying to decrease by a zero amount - not valid
|
||||||
|
let decrease_pledge_msg = VestingExecuteMsg::DecreasePledge {
|
||||||
|
amount: mix_coin(0),
|
||||||
|
};
|
||||||
|
let res_zero = test
|
||||||
|
.app
|
||||||
|
.execute_contract(
|
||||||
|
Addr::unchecked(vesting_account),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&decrease_pledge_msg,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap_err();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
VestingContractError::EmptyFunds,
|
||||||
|
res_zero.downcast().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
// trying to go below the cap - also not valid
|
||||||
|
let amount = mix_coin(50_000);
|
||||||
|
let decrease_pledge_msg = VestingExecuteMsg::DecreasePledge {
|
||||||
|
amount: amount.clone(),
|
||||||
|
};
|
||||||
|
let res_below = test
|
||||||
|
.app
|
||||||
|
.execute_contract(
|
||||||
|
Addr::unchecked(vesting_account),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&decrease_pledge_msg,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap_err();
|
||||||
|
assert_eq!(
|
||||||
|
MixnetContractError::InvalidPledgeReduction {
|
||||||
|
current: pledge.amount,
|
||||||
|
decrease_by: amount.amount,
|
||||||
|
minimum: minimum_pledge.amount,
|
||||||
|
denom: minimum_pledge.denom
|
||||||
|
},
|
||||||
|
res_below.downcast().unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decrease_mixnode_pledge_from_vesting_account_with_sufficient_pledge() {
|
||||||
|
let mut test = TestSetup::new_simple();
|
||||||
|
let vesting_account = "vesting-account";
|
||||||
|
|
||||||
|
// 1. create vesting account
|
||||||
|
let create_msg = VestingExecuteMsg::CreateAccount {
|
||||||
|
owner_address: vesting_account.to_string(),
|
||||||
|
staking_address: None,
|
||||||
|
vesting_spec: None,
|
||||||
|
cap: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
test.app
|
||||||
|
.execute_contract(
|
||||||
|
vesting_owner(),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&create_msg,
|
||||||
|
&mix_coins(10_000_000_000),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// 2. bond mixnode with the vesting account
|
||||||
|
let pledge = mix_coin(150_000_000);
|
||||||
|
|
||||||
|
let cost_params = MixNodeCostParams {
|
||||||
|
profit_margin_percent: Percent::from_percentage_value(10).unwrap(),
|
||||||
|
interval_operating_cost: mix_coin(40_000_000),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (mix_node, owner_signature) = test.valid_mixnode_with_sig(
|
||||||
|
vesting_account,
|
||||||
|
Some(test.vesting_contract()),
|
||||||
|
cost_params.clone(),
|
||||||
|
pledge.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let bond_msg = VestingExecuteMsg::BondMixnode {
|
||||||
|
mix_node,
|
||||||
|
cost_params,
|
||||||
|
owner_signature,
|
||||||
|
amount: pledge,
|
||||||
|
};
|
||||||
|
test.app
|
||||||
|
.execute_contract(
|
||||||
|
Addr::unchecked(vesting_account),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&bond_msg,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// 3. try to decrease the pledge
|
||||||
|
let before: MixOwnershipResponse = test
|
||||||
|
.app
|
||||||
|
.wrap()
|
||||||
|
.query_wasm_smart(
|
||||||
|
test.mixnet_contract(),
|
||||||
|
&MixnetQueryMsg::GetOwnedMixnode {
|
||||||
|
address: vesting_account.to_string(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let balance_before = test
|
||||||
|
.app
|
||||||
|
.wrap()
|
||||||
|
.query_balance(test.vesting_contract(), MIX_DENOM)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(balance_before.amount.u128(), 9_850_000_000);
|
||||||
|
|
||||||
|
let decrease_pledge_msg = VestingExecuteMsg::DecreasePledge {
|
||||||
|
amount: mix_coin(50_000_000),
|
||||||
|
};
|
||||||
|
test.app
|
||||||
|
.execute_contract(
|
||||||
|
Addr::unchecked(vesting_account),
|
||||||
|
test.vesting_contract(),
|
||||||
|
&decrease_pledge_msg,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let after_decrease: MixOwnershipResponse = test
|
||||||
|
.app
|
||||||
|
.wrap()
|
||||||
|
.query_wasm_smart(
|
||||||
|
test.mixnet_contract(),
|
||||||
|
&MixnetQueryMsg::GetOwnedMixnode {
|
||||||
|
address: vesting_account.to_string(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// note: nothing has changed with the pledge because the event hasn't been resolved yet!
|
||||||
|
assert_eq!(before.address, after_decrease.address);
|
||||||
|
let before_details = before.mixnode_details.unwrap();
|
||||||
|
let after_details = after_decrease.mixnode_details.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
before_details.rewarding_details,
|
||||||
|
after_details.rewarding_details
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
before_details.bond_information,
|
||||||
|
after_details.bond_information
|
||||||
|
);
|
||||||
|
|
||||||
|
// but we have the pending change saved now!
|
||||||
|
assert!(before_details.pending_changes.pledge_change.is_none());
|
||||||
|
assert_eq!(Some(1), after_details.pending_changes.pledge_change);
|
||||||
|
|
||||||
|
// 4. resolve events
|
||||||
|
test.advance_mixnet_epoch();
|
||||||
|
|
||||||
|
let balance_after = test
|
||||||
|
.app
|
||||||
|
.wrap()
|
||||||
|
.query_balance(test.vesting_contract(), MIX_DENOM)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(balance_after.amount.u128(), 9_900_000_000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::support::setup::{MIX_DENOM, REWARDING_VALIDATOR};
|
||||||
|
use cosmwasm_std::Decimal;
|
||||||
|
use nym_contracts_common::Percent;
|
||||||
|
use nym_mixnet_contract_common::InitialRewardingParams;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub fn default_mixnet_init_msg() -> nym_mixnet_contract_common::InstantiateMsg {
|
||||||
|
nym_mixnet_contract_common::InstantiateMsg {
|
||||||
|
rewarding_validator_address: REWARDING_VALIDATOR.to_string(),
|
||||||
|
vesting_contract_address: "placeholder".to_string(),
|
||||||
|
rewarding_denom: MIX_DENOM.to_string(),
|
||||||
|
epochs_in_interval: 720,
|
||||||
|
epoch_duration: Duration::from_secs(60 * 60),
|
||||||
|
initial_rewarding_params: InitialRewardingParams {
|
||||||
|
initial_reward_pool: Decimal::from_atomics(250_000_000_000_000u128, 0).unwrap(),
|
||||||
|
initial_staking_supply: Decimal::from_atomics(223_000_000_000_000u128, 0).unwrap(),
|
||||||
|
staking_supply_scale_factor: Percent::hundred(),
|
||||||
|
sybil_resistance: Percent::from_percentage_value(30).unwrap(),
|
||||||
|
active_set_work_factor: Decimal::from_atomics(10u32, 0).unwrap(),
|
||||||
|
interval_pool_emission: Percent::from_percentage_value(2).unwrap(),
|
||||||
|
rewarded_set_size: 240,
|
||||||
|
active_set_size: 100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user