Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28177d5d5d | |||
| 10b63f8667 | |||
| 9989c226ae | |||
| 31f85e61f0 | |||
| 73ac5eb19b | |||
| f1f06ceca2 | |||
| f5841b2b60 | |||
| 413ef2e11a | |||
| 96a4e8b636 | |||
| 4e79ef1b12 | |||
| b5956933d9 | |||
| 765589c444 | |||
| 38663e41c3 | |||
| 1463ddd339 | |||
| d9a2e87fc6 | |||
| 4630eb6cd4 | |||
| aa00711138 | |||
| 6b3292ddbc | |||
| a5214af0df | |||
| 34d25f4faf | |||
| 54e024962c | |||
| e552ebb736 | |||
| 39aa3b624f | |||
| 2d2121b331 |
@@ -8,6 +8,11 @@ on:
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
enable_wireguard:
|
||||
description: "Add --features wireguard"
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
enable_deb:
|
||||
description: "True to enable cargo-deb installation and .deb package building"
|
||||
required: false
|
||||
@@ -65,6 +70,9 @@ jobs:
|
||||
- name: Set CARGO_FEATURES
|
||||
run: |
|
||||
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
|
||||
if: >
|
||||
github.event_name == 'schedule' ||
|
||||
(github.event_name == 'workflow_dispatch' && inputs.enable_wireguard == true)
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
||||
@@ -51,10 +51,6 @@ jobs:
|
||||
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
|
||||
|
||||
- name: Set CARGO_FEATURES
|
||||
run: |
|
||||
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -64,8 +60,8 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release ${{ env.CARGO_FEATURES }}
|
||||
|
||||
args: --workspace --release
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
||||
+1
-70
@@ -4,76 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.10-caramello] (2024-08-19)
|
||||
|
||||
- bugfix: make sure DKG parses data out of events if logs are empty ([#4764])
|
||||
- Fix clippy on rustc beta toolchain ([#4746])
|
||||
- Fix clippy for beta toolchain ([#4742])
|
||||
- Disable testnet-manager on non-unix ([#4741])
|
||||
- Don't set NYM_VPN_API to default ([#4740])
|
||||
- Update publish-nym-binaries.yml ([#4739])
|
||||
- Update ci-build-upload-binaries.yml ([#4738])
|
||||
- Add NYM_VPN_API to network config ([#4736])
|
||||
- Re-export RecipientFormattingError in nym sdk ([#4735])
|
||||
- Persist wireguard peers ([#4732])
|
||||
- Fix tokio error in 1.39 ([#4730])
|
||||
- Feature/vesting purge plus ranged cost params ([#4716])
|
||||
- Fix (some) feature unification build failures ([#4681])
|
||||
- Feature Compact Ecash : The One PR ([#4623])
|
||||
|
||||
[#4764]: https://github.com/nymtech/nym/pull/4764
|
||||
[#4746]: https://github.com/nymtech/nym/pull/4746
|
||||
[#4742]: https://github.com/nymtech/nym/pull/4742
|
||||
[#4741]: https://github.com/nymtech/nym/pull/4741
|
||||
[#4740]: https://github.com/nymtech/nym/pull/4740
|
||||
[#4739]: https://github.com/nymtech/nym/pull/4739
|
||||
[#4738]: https://github.com/nymtech/nym/pull/4738
|
||||
[#4736]: https://github.com/nymtech/nym/pull/4736
|
||||
[#4735]: https://github.com/nymtech/nym/pull/4735
|
||||
[#4732]: https://github.com/nymtech/nym/pull/4732
|
||||
[#4730]: https://github.com/nymtech/nym/pull/4730
|
||||
[#4716]: https://github.com/nymtech/nym/pull/4716
|
||||
[#4681]: https://github.com/nymtech/nym/pull/4681
|
||||
[#4623]: https://github.com/nymtech/nym/pull/4623
|
||||
|
||||
## [2024.9-topdeck] (2024-07-26)
|
||||
|
||||
- chore: fix 1.80 lint issues ([#4731])
|
||||
- Handle clients with different versions in IPR ([#4723])
|
||||
- Add 1GB/day/user bandwidth cap ([#4717])
|
||||
- Feature/merge back ([#4710])
|
||||
- removed mixnode/gateway config migration code and disabled cli without explicit flag ([#4706])
|
||||
|
||||
[#4731]: https://github.com/nymtech/nym/pull/4731
|
||||
[#4723]: https://github.com/nymtech/nym/pull/4723
|
||||
[#4717]: https://github.com/nymtech/nym/pull/4717
|
||||
[#4710]: https://github.com/nymtech/nym/pull/4710
|
||||
[#4706]: https://github.com/nymtech/nym/pull/4706
|
||||
|
||||
## [2024.8-wispa] (2024-07-10)
|
||||
|
||||
- add event parsing to support cosmos_sdk > 0.50 ([#4697])
|
||||
- Fix NR config compatibility ([#4690])
|
||||
- Remove UserAgent constructor since it's weakly typed ([#4689])
|
||||
- [bugfix]: Node_api_check CLI looked over roles on blacklisted nodes ([#4687])
|
||||
- Add mixnodes to self describing api cache ([#4684])
|
||||
- Move and whole bump of crates to workspace and upgrade some ([#4680])
|
||||
- Remove code that refers to removed nym-network-statistics ([#4679])
|
||||
- Remove nym-network-statistics ([#4678])
|
||||
- Create UserAgent that can be passed from the binary to the nym api client ([#4677])
|
||||
- Add authenticator ([#4667])
|
||||
|
||||
[#4697]: https://github.com/nymtech/nym/pull/4697
|
||||
[#4690]: https://github.com/nymtech/nym/pull/4690
|
||||
[#4689]: https://github.com/nymtech/nym/pull/4689
|
||||
[#4687]: https://github.com/nymtech/nym/pull/4687
|
||||
[#4684]: https://github.com/nymtech/nym/pull/4684
|
||||
[#4680]: https://github.com/nymtech/nym/pull/4680
|
||||
[#4679]: https://github.com/nymtech/nym/pull/4679
|
||||
[#4678]: https://github.com/nymtech/nym/pull/4678
|
||||
[#4677]: https://github.com/nymtech/nym/pull/4677
|
||||
[#4667]: https://github.com/nymtech/nym/pull/4667
|
||||
|
||||
## [2024.7-doubledecker] (2024-07-04)
|
||||
|
||||
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
|
||||
@@ -583,6 +513,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#3187]: https://github.com/nymtech/nym/issues/3187
|
||||
[#3203]: https://github.com/nymtech/nym/pull/3203
|
||||
[#3199]: https://github.com/nymtech/nym/pull/3199
|
||||
>>>>>>> master
|
||||
|
||||
## [v1.1.13] (2023-03-15)
|
||||
|
||||
|
||||
Generated
+241
-143
File diff suppressed because it is too large
Load Diff
+8
-9
@@ -52,8 +52,6 @@ members = [
|
||||
"common/ecash-time",
|
||||
"common/execute",
|
||||
"common/exit-policy",
|
||||
"common/gateway-requests",
|
||||
"common/gateway-storage",
|
||||
"common/http-api-client",
|
||||
"common/http-api-common",
|
||||
"common/inclusion-probability",
|
||||
@@ -98,6 +96,7 @@ members = [
|
||||
"explorer-api/explorer-api-requests",
|
||||
"explorer-api/explorer-client",
|
||||
"gateway",
|
||||
"gateway/gateway-requests",
|
||||
"integrations/bity",
|
||||
"mixnode",
|
||||
"sdk/lib/socks5-listener",
|
||||
@@ -140,7 +139,7 @@ default-members = [
|
||||
"tools/nymvisor",
|
||||
"explorer-api",
|
||||
"nym-validator-rewarder",
|
||||
"nym-node",
|
||||
"nym-node"
|
||||
]
|
||||
|
||||
exclude = [
|
||||
@@ -291,11 +290,11 @@ tar = "0.4.40"
|
||||
tempfile = "3.5.0"
|
||||
thiserror = "1.0.48"
|
||||
time = "0.3.30"
|
||||
tokio = "1.39"
|
||||
tokio-stream = "0.1.15"
|
||||
tokio-test = "0.4.4"
|
||||
tokio = "1.33.0"
|
||||
tokio-stream = "0.1.14"
|
||||
tokio-test = "0.4.2"
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = "0.7.11"
|
||||
tokio-util = "0.7.10"
|
||||
toml = "0.8.14"
|
||||
tower = "0.4.13"
|
||||
tower-http = "0.5.2"
|
||||
@@ -347,8 +346,8 @@ bip32 = { version = "0.5.1", default-features = false }
|
||||
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
|
||||
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
|
||||
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
|
||||
tendermint = "0.37.0" # same version as used by cosmrs
|
||||
tendermint-rpc = "0.37.0" # same version as used by cosmrs
|
||||
tendermint = "0.37.0" # same version as used by cosmrs
|
||||
tendermint-rpc = "0.37.0" # same version as used by cosmrs
|
||||
prost = { version = "0.12", default-features = false }
|
||||
|
||||
# wasm-related dependencies
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.37"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -26,46 +26,30 @@ clap = { workspace = true, features = ["cargo", "derive"] }
|
||||
dirs = { workspace = true }
|
||||
log = { workspace = true } # self explanatory
|
||||
rand = { workspace = true }
|
||||
serde = { workspace = true, features = [
|
||||
"derive",
|
||||
] } # for config serialization/deserialization
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = [
|
||||
"rt-multi-thread",
|
||||
"net",
|
||||
"signal",
|
||||
] } # async runtime
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
|
||||
tokio-tungstenite = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
## internal
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"output_format",
|
||||
"clap",
|
||||
] }
|
||||
nym-client-core = { path = "../../common/client-core", features = [
|
||||
"fs-credentials-storage",
|
||||
"fs-surb-storage",
|
||||
"fs-gateways-storage",
|
||||
"cli",
|
||||
] }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "clap"] }
|
||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-gateway-requests = { path = "../../common/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||
"http-client",
|
||||
] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
|
||||
nym-client-websocket-requests = { path = "websocket-requests" }
|
||||
nym-id = { path = "../../common/nym-id" }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.37"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
@@ -11,9 +11,7 @@ license.workspace = true
|
||||
bs58 = { workspace = true }
|
||||
clap = { workspace = true, features = ["cargo", "derive"] }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true, features = [
|
||||
"derive",
|
||||
] } # for config serialization/deserialization
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
serde_json = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
@@ -24,21 +22,13 @@ url = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"output_format",
|
||||
"clap",
|
||||
] }
|
||||
nym-client-core = { path = "../../common/client-core", features = [
|
||||
"fs-credentials-storage",
|
||||
"fs-surb-storage",
|
||||
"fs-gateways-storage",
|
||||
"cli",
|
||||
] }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
|
||||
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-gateway-requests = { path = "../../common/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-id = { path = "../../common/nym-id" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
@@ -46,9 +36,7 @@ nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||
"http-client",
|
||||
] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
use crate::utils::{
|
||||
get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures,
|
||||
};
|
||||
use crate::utils::{get_coin_index_signatures, get_expiration_date_signatures};
|
||||
use log::info;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
|
||||
use nym_credentials::ecash::utils::obtain_aggregate_wallet;
|
||||
use nym_credentials::IssuedTicketBook;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_ecash_time::{ecash_default_expiration_date, Date};
|
||||
use nym_validator_client::coconut::all_ecash_api_clients;
|
||||
@@ -25,7 +22,6 @@ pub async fn make_deposit<C>(
|
||||
client: &C,
|
||||
client_id: &[u8],
|
||||
expiration: Option<Date>,
|
||||
ticketbook_type: TicketType,
|
||||
) -> Result<IssuanceTicketBook, BandwidthControllerError>
|
||||
where
|
||||
C: EcashSigningClient + EcashQueryClient + Sync,
|
||||
@@ -52,12 +48,11 @@ where
|
||||
deposit_id,
|
||||
client_id,
|
||||
signing_key,
|
||||
ticketbook_type,
|
||||
expiration,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn query_and_persist_required_global_data<S>(
|
||||
pub async fn query_and_persist_required_global_signatures<S>(
|
||||
storage: &S,
|
||||
epoch_id: EpochId,
|
||||
expiration_date: Date,
|
||||
@@ -67,10 +62,6 @@ where
|
||||
S: Storage,
|
||||
<S as Storage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
log::info!("Getting master verification key");
|
||||
// this will also persist the key in the storage if was not there already
|
||||
get_aggregate_verification_key(storage, epoch_id, apis.clone()).await?;
|
||||
|
||||
log::info!("Getting expiration date signatures");
|
||||
// this will also persist the signatures in the storage if they were not there already
|
||||
get_expiration_date_signatures(storage, epoch_id, expiration_date, apis.clone()).await?;
|
||||
|
||||
@@ -16,7 +16,7 @@ use nym_credential_storage::models::RetrievedTicketbook;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::ecash::bandwidth::CredentialSpendingData;
|
||||
use nym_credentials_interface::{
|
||||
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
|
||||
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, NymPayInfo, VerificationKeyAuth,
|
||||
};
|
||||
use nym_ecash_time::Date;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -165,9 +165,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
||||
.get_coin_index_signatures(epoch_id, &mut api_clients)
|
||||
.await?;
|
||||
|
||||
let pay_info = retrieved_ticketbook
|
||||
.ticketbook
|
||||
.generate_pay_info(provider_pk);
|
||||
let pay_info = NymPayInfo::generate(provider_pk);
|
||||
|
||||
let spend_request = retrieved_ticketbook.ticketbook.prepare_for_spending(
|
||||
&verification_key,
|
||||
|
||||
@@ -38,7 +38,7 @@ nym-country-group = { path = "../country-group" }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
|
||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||
nym-gateway-requests = { path = "../gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-metrics = { path = "../nym-metrics" }
|
||||
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
@@ -46,12 +46,9 @@ nym-pemstore = { path = "../pemstore" }
|
||||
nym-topology = { path = "../topology", features = ["serializable"] }
|
||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||
nym-task = { path = "../task" }
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-client-core-config-types = { path = "./config-types", features = [
|
||||
"disk-persistence",
|
||||
] }
|
||||
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"] }
|
||||
nym-client-core-surb-storage = { path = "./surb-storage" }
|
||||
nym-client-core-gateways-storage = { path = "./gateways-storage" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
@@ -118,7 +115,6 @@ tempfile = { workspace = true }
|
||||
[features]
|
||||
default = []
|
||||
cli = ["clap", "comfy-table"]
|
||||
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
|
||||
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
|
||||
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
|
||||
wasm = ["nym-gateway-client/wasm"]
|
||||
|
||||
@@ -18,7 +18,7 @@ url.workspace = true
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
|
||||
nym-crypto = { path = "../../crypto", features = ["asymmetric"] }
|
||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||
workspace = true
|
||||
@@ -27,12 +27,7 @@ optional = true
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
|
||||
|
||||
[features]
|
||||
fs-gateways-storage = ["sqlx"]
|
||||
fs-gateways-storage = ["sqlx"]
|
||||
@@ -5,15 +5,14 @@ use crate::cli_helpers::{CliClient, CliClientConfig};
|
||||
use crate::error::ClientCoreError;
|
||||
use nym_credential_storage::models::BasicTicketbookInformation;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_ecash_time::ecash_today;
|
||||
use nym_network_defaults::TicketbookType::MixnetEntry;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::Date;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AvailableTicketbook {
|
||||
pub id: i64,
|
||||
pub typ: TicketType,
|
||||
pub expiration: Date,
|
||||
pub issued_tickets: u32,
|
||||
pub claimed_tickets: u32,
|
||||
@@ -46,7 +45,6 @@ impl AvailableTicketbook {
|
||||
|
||||
vec![
|
||||
comfy_table::Cell::new(self.id.to_string()),
|
||||
comfy_table::Cell::new(self.typ),
|
||||
expiration,
|
||||
comfy_table::Cell::new(format!("{issued} ({si_issued})")),
|
||||
comfy_table::Cell::new(format!("{claimed} ({si_claimed})")),
|
||||
@@ -57,22 +55,17 @@ impl AvailableTicketbook {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<BasicTicketbookInformation> for AvailableTicketbook {
|
||||
type Error = ClientCoreError;
|
||||
|
||||
fn try_from(value: BasicTicketbookInformation) -> Result<Self, Self::Error> {
|
||||
let typ = value
|
||||
.ticketbook_type
|
||||
.parse()
|
||||
.map_err(|_| ClientCoreError::UnknownTicketType)?;
|
||||
Ok(AvailableTicketbook {
|
||||
impl From<BasicTicketbookInformation> for AvailableTicketbook {
|
||||
fn from(value: BasicTicketbookInformation) -> Self {
|
||||
AvailableTicketbook {
|
||||
id: value.id,
|
||||
typ,
|
||||
expiration: value.expiration_date,
|
||||
issued_tickets: value.total_tickets,
|
||||
claimed_tickets: value.used_tickets,
|
||||
ticket_size: typ.to_repr().bandwidth_value(),
|
||||
})
|
||||
|
||||
// TODO: this will change when 'type' field is introduced; for now doesn't matter what we put there
|
||||
ticket_size: MixnetEntry.bandwidth_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +79,6 @@ impl std::fmt::Display for AvailableTicketbooks {
|
||||
let mut table = comfy_table::Table::new();
|
||||
table.set_header(vec![
|
||||
"id",
|
||||
"type",
|
||||
"expiration",
|
||||
"issued tickets (bandwidth)",
|
||||
"claimed tickets (bandwidth)",
|
||||
@@ -132,9 +124,6 @@ where
|
||||
})?;
|
||||
|
||||
Ok(AvailableTicketbooks(
|
||||
ticketbooks
|
||||
.into_iter()
|
||||
.map(TryInto::<AvailableTicketbook>::try_into)
|
||||
.collect::<Result<_, _>>()?,
|
||||
ticketbooks.into_iter().map(Into::into).collect(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
config::{self, disk_persistence::CommonClientPaths},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-credentials-storage"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
|
||||
|
||||
pub use nym_client_core_gateways_storage as gateways_storage;
|
||||
|
||||
@@ -68,9 +68,6 @@ pub enum ClientCoreError {
|
||||
source: Box<dyn Error + Send + Sync>,
|
||||
},
|
||||
|
||||
#[error("the provided ticket type is invalid")]
|
||||
UnknownTicketType,
|
||||
|
||||
#[error("the gateway id is invalid - {0}")]
|
||||
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
|
||||
|
||||
|
||||
@@ -2,9 +2,7 @@ use std::future::Future;
|
||||
|
||||
#[cfg(all(
|
||||
not(target_arch = "wasm32"),
|
||||
feature = "cli",
|
||||
feature = "fs-surb-storage",
|
||||
feature = "fs-credentials-storage",
|
||||
feature = "fs-gateways-storage"
|
||||
))]
|
||||
pub mod cli_helpers;
|
||||
|
||||
@@ -24,7 +24,7 @@ nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
||||
nym-credentials = { path = "../../credentials" }
|
||||
nym-credential-storage = { path = "../../credential-storage" }
|
||||
nym-crypto = { path = "../../crypto" }
|
||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
nym-pemstore = { path = "../../pemstore" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::GatewayClientError;
|
||||
use nym_network_defaults::TicketTypeRepr::V1MixnetEntry;
|
||||
use nym_network_defaults::TicketbookType::MixnetEntry;
|
||||
use si_scale::helpers::bibytes2;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -103,7 +103,7 @@ impl BandwidthTickets {
|
||||
|
||||
// 20% of entry ticket value
|
||||
pub const DEFAULT_REMAINING_BANDWIDTH_THRESHOLD: i64 =
|
||||
(V1MixnetEntry.bandwidth_value() / 5) as i64;
|
||||
(MixnetEntry.bandwidth_value() / 5) as i64;
|
||||
|
||||
pub const DEFAULT_CUTOFF_REMAINING_BANDWIDTH_THRESHOLD: Option<i64> = None;
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ use nym_api_requests::ecash::VerificationKeyResponse;
|
||||
pub use nym_api_requests::{
|
||||
ecash::{
|
||||
models::{
|
||||
EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse,
|
||||
IssuedTicketbook, IssuedTicketbookBody, SpentCredentialsResponse,
|
||||
EpochCredentialsResponse, IssuedCredential, IssuedCredentialBody,
|
||||
IssuedCredentialResponse, IssuedCredentialsResponse, SpentCredentialsResponse,
|
||||
},
|
||||
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody,
|
||||
PartialCoinIndicesSignatureResponse, PartialExpirationDateSignatureResponse,
|
||||
|
||||
@@ -683,24 +683,6 @@ pub trait MixnetSigningClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn migrate_vested_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateVestedMixNode {}, vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn migrate_vested_delegation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::MigrateVestedDelegation { mix_id },
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "contract-testing")]
|
||||
async fn testing_resolve_all_pending_events(
|
||||
&self,
|
||||
@@ -946,12 +928,6 @@ mod tests {
|
||||
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
|
||||
.withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None)
|
||||
.ignore(),
|
||||
MixnetExecuteMsg::MigrateVestedMixNode { .. } => {
|
||||
client.migrate_vested_mixnode(None).ignore()
|
||||
}
|
||||
MixnetExecuteMsg::MigrateVestedDelegation { mix_id } => {
|
||||
client.migrate_vested_delegation(mix_id, None).ignore()
|
||||
}
|
||||
|
||||
#[cfg(feature = "contract-testing")]
|
||||
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
|
||||
|
||||
@@ -437,7 +437,6 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
|
||||
use nym_vesting_contract_common::ExecuteMsg;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
@@ -561,9 +560,6 @@ mod tests {
|
||||
VestingExecuteMsg::UpdateLockedPledgeCap { address, cap } => client
|
||||
.update_locked_pledge_cap(address.parse().unwrap(), cap, None)
|
||||
.ignore(),
|
||||
// those will never be manually called by clients
|
||||
ExecuteMsg::TrackMigratedMixnode { .. } => "explicitly_ignored".ignore(),
|
||||
ExecuteMsg::TrackMigratedDelegation { .. } => "explicitly_ignored".ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use cosmrs::abci::TxMsgData;
|
||||
use cosmrs::cosmwasm::MsgExecuteContractResponse;
|
||||
@@ -10,6 +9,7 @@ use log::error;
|
||||
use prost::bytes::Bytes;
|
||||
use tendermint_rpc::endpoint::broadcast;
|
||||
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
pub use cosmrs::abci::MsgResponse;
|
||||
|
||||
pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
|
||||
|
||||
@@ -21,8 +21,7 @@ pub struct Log {
|
||||
|
||||
/// Searches in logs for the first event of the given event type and in that event
|
||||
/// for the first attribute with the given attribute key.
|
||||
#[deprecated]
|
||||
pub fn find_attribute_in_logs<'a>(
|
||||
pub fn find_attribute<'a>(
|
||||
logs: &'a [Log],
|
||||
event_type: &str,
|
||||
attribute_key: &str,
|
||||
@@ -36,7 +35,6 @@ pub fn find_attribute_in_logs<'a>(
|
||||
}
|
||||
|
||||
/// Search for the proposal id in the given log. It'll be in the LAST wasm event, with attribute key "proposal_id"
|
||||
#[deprecated]
|
||||
pub fn find_proposal_id(logs: &[Log]) -> Result<u64, NyxdError> {
|
||||
let maybe_attributes = logs
|
||||
.iter()
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TEMPORARY WORKAROUND:
|
||||
// those features are expected as the below should only get activated whenever
|
||||
// the corresponding features in tendermint-rpc are enabled transitively
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
use crate::nyxd::cosmwasm_client::client_traits::SigningCosmWasmClient;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Config, GasPrice, Hash, Height};
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::cosmwasm_client::logs::Log;
|
||||
use crate::nyxd::TxResponse;
|
||||
use cosmrs::tendermint::abci;
|
||||
|
||||
pub use abci::Event;
|
||||
|
||||
// Searches in events for an event of the given event type which contains an
|
||||
// attribute for with the given key.
|
||||
pub fn find_tx_attribute(tx: &TxResponse, event_type: &str, attribute_key: &str) -> Option<String> {
|
||||
find_event_attribute(&tx.tx_result.events, event_type, attribute_key)
|
||||
}
|
||||
|
||||
pub fn find_event_attribute(
|
||||
events: &[Event],
|
||||
event_type: &str,
|
||||
attribute_key: &str,
|
||||
) -> Option<String> {
|
||||
let event = events.iter().find(|e| e.kind == event_type)?;
|
||||
let event = tx.tx_result.events.iter().find(|e| e.kind == event_type)?;
|
||||
let attribute = event.attributes.iter().find(|&attr| {
|
||||
if let Ok(key_str) = attr.key_str() {
|
||||
key_str == attribute_key
|
||||
@@ -28,23 +16,3 @@ pub fn find_event_attribute(
|
||||
})?;
|
||||
Some(attribute.value_str().ok().map(|str| str.to_string())).flatten()
|
||||
}
|
||||
|
||||
pub fn find_attribute_value_in_logs_or_events(
|
||||
logs: &[Log],
|
||||
events: &[Event],
|
||||
event_type: &str,
|
||||
attribute_key: &str,
|
||||
) -> Option<String> {
|
||||
// if logs are empty, i.e. we're using post 0.50 code, parse the events instead
|
||||
if !logs.is_empty() {
|
||||
#[allow(deprecated)]
|
||||
return crate::nyxd::cosmwasm_client::logs::find_attribute_in_logs(
|
||||
logs,
|
||||
event_type,
|
||||
attribute_key,
|
||||
)
|
||||
.map(|attr| attr.value.clone());
|
||||
}
|
||||
|
||||
find_event_attribute(events, event_type, attribute_key)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TEMPORARY WORKAROUND:
|
||||
// those features are expected as the below should only get activated whenever
|
||||
// the corresponding features in tendermint-rpc are enabled transitively
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
use crate::nyxd::contract_traits::{NymContractsProvider, TypedNymContracts};
|
||||
use crate::nyxd::cosmwasm_client::types::{
|
||||
ChangeAdminResult, ContractCodeId, ExecuteResult, InstantiateOptions, InstantiateResult,
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TEMPORARY WORKAROUND:
|
||||
// those features are expected as the below should only get activated whenever
|
||||
// the corresponding features in tendermint-rpc are enabled transitively
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::tendermint::{self, abci, block::Height, evidence::Evidence, Genesis, Hash};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
@@ -7,10 +7,9 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
base64 = "0.13.0"
|
||||
bip39 = { workspace = true }
|
||||
bs58 = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
comfy-table = { workspace = true }
|
||||
cfg-if = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
@@ -22,13 +21,13 @@ humantime-serde = { workspace = true }
|
||||
inquire = { workspace = true }
|
||||
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
|
||||
log = { workspace = true }
|
||||
rand = { workspace = true, features = ["std"] }
|
||||
rand = {version = "0.6", features = ["std"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
time = { workspace = true, features = ["parsing", "formatting"] }
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
toml = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync"]}
|
||||
toml = "0.5.6"
|
||||
url = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
+5
-13
@@ -9,17 +9,9 @@ use nym_credential_storage::initialise_persistent_storage;
|
||||
use nym_id::import_credential;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CredentialDataWrapper(Vec<u8>);
|
||||
|
||||
impl FromStr for CredentialDataWrapper {
|
||||
type Err = bs58::decode::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
bs58::decode(s).into_vec().map(CredentialDataWrapper)
|
||||
}
|
||||
fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
|
||||
bs58::decode(raw).into_vec()
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -30,8 +22,8 @@ pub struct Args {
|
||||
pub(crate) client_config: PathBuf,
|
||||
|
||||
/// Explicitly provide the encoded credential data (as base58)
|
||||
#[clap(long, group = "cred_data")]
|
||||
pub(crate) credential_data: Option<CredentialDataWrapper>,
|
||||
#[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)]
|
||||
pub(crate) credential_data: Option<Vec<u8>>,
|
||||
|
||||
/// Specifies the path to file containing binary credential data
|
||||
#[clap(long, group = "cred_data")]
|
||||
@@ -60,7 +52,7 @@ pub async fn execute(args: Args) -> anyhow::Result<()> {
|
||||
let credentials_store = initialise_persistent_storage(credentials_store).await;
|
||||
|
||||
let raw_credential = match args.credential_data {
|
||||
Some(data) => data.0,
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// SAFETY: one of those arguments must have been set
|
||||
fs::read(args.credential_path.unwrap())?
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use crate::utils::CommonConfigsWrapper;
|
||||
use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use nym_credential_storage::initialise_persistent_storage;
|
||||
use nym_credential_utils::utils;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Config file of the client that is supposed to use the credential.
|
||||
#[clap(long)]
|
||||
pub(crate) client_config: PathBuf,
|
||||
}
|
||||
|
||||
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
|
||||
|
||||
if let Ok(id) = loaded.try_get_id() {
|
||||
println!("loaded config file for client '{id}'");
|
||||
}
|
||||
|
||||
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
|
||||
bail!("the loaded config does not have a credentials store information")
|
||||
};
|
||||
|
||||
let Ok(private_id_key) = loaded.try_get_private_id_key() else {
|
||||
bail!("the loaded config does not have a public id key information")
|
||||
};
|
||||
|
||||
println!(
|
||||
"using credentials store at '{}'",
|
||||
credentials_store.display()
|
||||
);
|
||||
|
||||
let persistent_storage = initialise_persistent_storage(credentials_store).await;
|
||||
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
|
||||
utils::issue_credential(&client, &persistent_storage, &private_id_key.to_bytes()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
pub mod generate_ticket;
|
||||
pub mod import_ticket_book;
|
||||
pub mod issue_ticket_book;
|
||||
pub mod recover_ticket_book;
|
||||
@@ -20,5 +19,4 @@ pub enum EcashCommands {
|
||||
IssueTicketBook(issue_ticket_book::Args),
|
||||
RecoverTicketBook(recover_ticket_book::Args),
|
||||
ImportTicketBook(import_ticket_book::Args),
|
||||
GenerateTicket(generate_ticket::Args),
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::utils::CommonConfigsWrapper;
|
||||
use anyhow::{anyhow, bail};
|
||||
use clap::Parser;
|
||||
use colored::Colorize;
|
||||
use comfy_table::Table;
|
||||
use nym_credential_storage::initialise_persistent_storage;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Specify the index of the ticket to retrieve from the ticketbook.
|
||||
/// By default, the current unspent value is used.
|
||||
#[clap(long, group = "output")]
|
||||
pub(crate) ticket_index: Option<u64>,
|
||||
|
||||
/// Specify whether we should display payments for ALL available tickets
|
||||
#[clap(long, group = "output")]
|
||||
pub(crate) full: bool,
|
||||
|
||||
/// Base58-encoded identity of the provider (must be 32 bytes long)
|
||||
#[clap(long)]
|
||||
pub(crate) provider: String,
|
||||
|
||||
/// Config file of the client that is supposed to use the credential.
|
||||
#[clap(long, group = "source")]
|
||||
pub(crate) client_config: Option<PathBuf>,
|
||||
|
||||
/// Path to the dedicated credential storage database
|
||||
#[clap(long, group = "source")]
|
||||
pub(crate) credential_storage: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub async fn execute(args: Args) -> anyhow::Result<()> {
|
||||
let credentials_store = if let Some(explicit) = args.credential_storage {
|
||||
explicit
|
||||
} else {
|
||||
// SAFETY: at least one of them MUST HAVE been specified
|
||||
let cfg = args.client_config.unwrap();
|
||||
|
||||
let loaded = CommonConfigsWrapper::try_load(cfg)?;
|
||||
|
||||
if let Ok(id) = loaded.try_get_id() {
|
||||
println!("loaded config file for client '{id}'");
|
||||
}
|
||||
|
||||
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
|
||||
bail!("the loaded config does not have a credentials store information")
|
||||
};
|
||||
credentials_store
|
||||
};
|
||||
|
||||
let decoded_provider = bs58::decode(&args.provider).into_vec()?;
|
||||
if decoded_provider.len() != 32 {
|
||||
bail!("the provided provider information is malformed")
|
||||
}
|
||||
let provider_arr: [u8; 32] = decoded_provider.try_into().unwrap();
|
||||
|
||||
let persistent_storage = initialise_persistent_storage(&credentials_store).await;
|
||||
let Some(mut next_ticketbook) = persistent_storage
|
||||
.get_next_unspent_usable_ticketbook(0)
|
||||
.await?
|
||||
else {
|
||||
bail!(
|
||||
"there are no valid ticketbooks in the storage at {}",
|
||||
credentials_store.display()
|
||||
)
|
||||
};
|
||||
|
||||
let epoch_id = next_ticketbook.ticketbook.epoch_id();
|
||||
let expiration_date = next_ticketbook.ticketbook.expiration_date();
|
||||
|
||||
let verification_key = persistent_storage
|
||||
.get_master_verification_key(epoch_id)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
anyhow!("ticketbook got incorrectly imported - the master verification key is missing")
|
||||
})?;
|
||||
let expiration_signatures = persistent_storage
|
||||
.get_expiration_date_signatures(expiration_date)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"ticketbook got incorrectly imported - the expiration date signatures are missing"
|
||||
)
|
||||
})?;
|
||||
let coin_indices_signatures = persistent_storage
|
||||
.get_coin_index_signatures(epoch_id)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
anyhow!("ticketbook got incorrectly imported - the coin index signatures are missing")
|
||||
})?;
|
||||
|
||||
let ticketbook_data = next_ticketbook.ticketbook.pack();
|
||||
|
||||
let next_ticket = args
|
||||
.ticket_index
|
||||
.unwrap_or(next_ticketbook.ticketbook.spent_tickets());
|
||||
let pay_info = next_ticketbook.ticketbook.generate_pay_info(provider_arr);
|
||||
|
||||
println!("{}", "TICKETBOOK DATA:".bold());
|
||||
println!("{}", bs58::encode(&ticketbook_data.data).into_string());
|
||||
println!();
|
||||
|
||||
// display it only for a single ticket
|
||||
if !args.full {
|
||||
println!("attempting to generate payment for ticket {next_ticket}...");
|
||||
println!();
|
||||
next_ticketbook.ticketbook.update_spent_tickets(next_ticket);
|
||||
|
||||
let req = next_ticketbook.ticketbook.prepare_for_spending(
|
||||
&verification_key,
|
||||
pay_info.into(),
|
||||
&coin_indices_signatures,
|
||||
&expiration_signatures,
|
||||
1,
|
||||
)?;
|
||||
|
||||
let payment = req.payment;
|
||||
|
||||
println!("{}", format!("PAYMENT FOR TICKET {next_ticket}: ").bold());
|
||||
println!("{}", bs58::encode(&payment.to_bytes()).into_string());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!(
|
||||
"generating payment information for {} tickets. this might take a while!...",
|
||||
next_ticketbook.ticketbook.params_total_tickets()
|
||||
);
|
||||
|
||||
// otherwise generate all the payments
|
||||
let last_spent = next_ticketbook.ticketbook.spent_tickets();
|
||||
|
||||
let mut table = Table::new();
|
||||
table.set_header(vec!["index", "binary data", "spend status"]);
|
||||
|
||||
for i in 0..next_ticketbook.ticketbook.params_total_tickets() {
|
||||
let status = if i < last_spent {
|
||||
"SPENT".red()
|
||||
} else {
|
||||
"NOT SPENT".green()
|
||||
};
|
||||
|
||||
next_ticketbook.ticketbook.update_spent_tickets(i);
|
||||
|
||||
let req = next_ticketbook.ticketbook.prepare_for_spending(
|
||||
&verification_key,
|
||||
pay_info.into(),
|
||||
&coin_indices_signatures,
|
||||
&expiration_signatures,
|
||||
1,
|
||||
)?;
|
||||
|
||||
let payment = req.payment;
|
||||
let payment_bytes = payment.to_bytes();
|
||||
let len = payment_bytes.len();
|
||||
let display_size = 100;
|
||||
let remaining = len - display_size;
|
||||
|
||||
table.add_row(vec![
|
||||
i.to_string(),
|
||||
format!(
|
||||
"{}…{remaining}bytes remaining",
|
||||
bs58::encode(&payment_bytes[..display_size]).into_string()
|
||||
),
|
||||
status.to_string(),
|
||||
]);
|
||||
}
|
||||
|
||||
println!("{}", "AVAILABLE TICKETS".bold());
|
||||
println!("{table}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use crate::utils::CommonConfigsWrapper;
|
||||
use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use nym_credential_storage::initialise_persistent_storage;
|
||||
use nym_credential_utils::utils;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Specify which type of ticketbook should be issued
|
||||
#[clap(long, default_value_t = TicketType::default())]
|
||||
pub(crate) ticketbook_type: TicketType,
|
||||
|
||||
/// Config file of the client that is supposed to use the credential.
|
||||
#[clap(long, group = "output")]
|
||||
pub(crate) client_config: Option<PathBuf>,
|
||||
|
||||
/// Path to the dedicated credential storage database
|
||||
#[clap(long, group = "output")]
|
||||
pub(crate) credential_storage: Option<PathBuf>,
|
||||
}
|
||||
|
||||
async fn issue_client_ticketbook(
|
||||
cfg: PathBuf,
|
||||
typ: TicketType,
|
||||
client: SigningClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let loaded = CommonConfigsWrapper::try_load(cfg)?;
|
||||
|
||||
if let Ok(id) = loaded.try_get_id() {
|
||||
println!("loaded config file for client '{id}'");
|
||||
}
|
||||
|
||||
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
|
||||
bail!("the loaded config does not have a credentials store information")
|
||||
};
|
||||
|
||||
let Ok(private_id_key) = loaded.try_get_private_id_key() else {
|
||||
bail!("the loaded config does not have a public id key information")
|
||||
};
|
||||
|
||||
println!(
|
||||
"using credentials store at '{}'",
|
||||
credentials_store.display()
|
||||
);
|
||||
|
||||
let persistent_storage = initialise_persistent_storage(credentials_store).await;
|
||||
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
|
||||
utils::issue_credential(
|
||||
&client,
|
||||
&persistent_storage,
|
||||
&private_id_key.to_bytes(),
|
||||
typ,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn issue_standalone_ticketbook(
|
||||
credentials_store: PathBuf,
|
||||
typ: TicketType,
|
||||
client: SigningClient,
|
||||
) -> anyhow::Result<()> {
|
||||
println!("attempting to issue a standalone ticketbook");
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut random_seed = [0u8; 32];
|
||||
rng.fill_bytes(&mut random_seed);
|
||||
|
||||
if let Some(parent) = credentials_store.parent() {
|
||||
create_dir_all(parent)?;
|
||||
}
|
||||
|
||||
let persistent_storage = initialise_persistent_storage(credentials_store).await;
|
||||
utils::issue_credential(&client, &persistent_storage, &random_seed, typ).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
match (args.client_config, args.credential_storage) {
|
||||
(Some(cfg), None) => issue_client_ticketbook(cfg, args.ticketbook_type, client).await,
|
||||
(None, Some(storage)) => {
|
||||
issue_standalone_ticketbook(storage, args.ticketbook_type, client).await
|
||||
}
|
||||
_ => unreachable!("clap should have made this branch impossible to reach!"),
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod coconut;
|
||||
pub mod context;
|
||||
pub mod ecash;
|
||||
pub mod utils;
|
||||
pub mod validator;
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use cosmwasm_std::Decimal;
|
||||
use log::{debug, info};
|
||||
use nym_mixnet_contract_common::{
|
||||
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
|
||||
};
|
||||
use nym_network_defaults::mainnet::MIX_DENOM;
|
||||
use nym_network_defaults::TOTAL_SUPPLY;
|
||||
use nym_validator_client::nyxd::{AccountId, Coin};
|
||||
|
||||
use cosmwasm_std::Decimal;
|
||||
use nym_mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent};
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn default_maximum_operating_cost() -> Coin {
|
||||
Coin::new(TOTAL_SUPPLY, MIX_DENOM.base)
|
||||
}
|
||||
|
||||
pub fn default_minimum_operating_cost() -> Coin {
|
||||
Coin::new(0, MIX_DENOM.base)
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
@@ -61,18 +50,6 @@ pub struct Args {
|
||||
|
||||
#[clap(long, default_value_t = 240)]
|
||||
pub active_set_size: u32,
|
||||
|
||||
#[clap(long, default_value_t = Percent::zero())]
|
||||
pub minimum_profit_margin_percent: Percent,
|
||||
|
||||
#[clap(long, default_value_t = Percent::hundred())]
|
||||
pub maximum_profit_margin_percent: Percent,
|
||||
|
||||
#[clap(long, default_value_t = default_minimum_operating_cost())]
|
||||
pub minimum_interval_operating_cost: Coin,
|
||||
|
||||
#[clap(long, default_value_t = default_maximum_operating_cost())]
|
||||
pub maximum_interval_operating_cost: Coin,
|
||||
}
|
||||
|
||||
pub async fn generate(args: Args) {
|
||||
@@ -120,10 +97,6 @@ pub async fn generate(args: Args) {
|
||||
.expect("Rewarding (mix) denom has to be set")
|
||||
});
|
||||
|
||||
if args.minimum_interval_operating_cost.denom != args.maximum_interval_operating_cost.denom {
|
||||
panic!("different denoms for operating cost bounds")
|
||||
}
|
||||
|
||||
let instantiate_msg = InstantiateMsg {
|
||||
rewarding_validator_address: rewarding_validator_address.to_string(),
|
||||
vesting_contract_address: vesting_contract_address.to_string(),
|
||||
@@ -131,14 +104,6 @@ pub async fn generate(args: Args) {
|
||||
epochs_in_interval: args.epochs_in_interval,
|
||||
epoch_duration: Duration::from_secs(args.epoch_duration),
|
||||
initial_rewarding_params,
|
||||
profit_margin: ProfitMarginRange {
|
||||
minimum: args.minimum_profit_margin_percent,
|
||||
maximum: args.maximum_profit_margin_percent,
|
||||
},
|
||||
interval_operating_cost: OperatingCostRange {
|
||||
minimum: args.minimum_interval_operating_cost.amount.into(),
|
||||
maximum: args.maximum_interval_operating_cost.amount.into(),
|
||||
},
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::MixId;
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
pub mix_id: Option<MixId>,
|
||||
|
||||
#[clap(long)]
|
||||
pub identity_key: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn migrate_vested_delegation(args: Args, client: SigningClient) {
|
||||
let mix_id = match args.mix_id {
|
||||
Some(mix_id) => mix_id,
|
||||
None => {
|
||||
let identity_key = args
|
||||
.identity_key
|
||||
.expect("either mix_id or mix_identity has to be specified");
|
||||
let node_details = client
|
||||
.get_mixnode_details_by_identity(identity_key)
|
||||
.await
|
||||
.expect("contract query failed")
|
||||
.mixnode_details
|
||||
.expect("mixnode with the specified identity doesnt exist");
|
||||
node_details.mix_id()
|
||||
}
|
||||
};
|
||||
|
||||
let res = client
|
||||
.migrate_vested_delegation(mix_id, None)
|
||||
.await
|
||||
.expect("failed to migrate delegation!");
|
||||
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
@@ -7,7 +7,6 @@ pub mod rewards;
|
||||
|
||||
pub mod delegate_to_mixnode;
|
||||
pub mod delegate_to_multiple_mixnodes;
|
||||
pub mod migrate_vested_delegation;
|
||||
pub mod query_for_delegations;
|
||||
pub mod undelegate_from_mixnode;
|
||||
pub mod vesting_delegate_to_mixnode;
|
||||
@@ -36,6 +35,4 @@ pub enum MixnetDelegatorsCommands {
|
||||
DelegateVesting(vesting_delegate_to_mixnode::Args),
|
||||
/// Undelegate from a mixnode (when originally using locked tokens)
|
||||
UndelegateVesting(vesting_undelegate_from_mixnode::Args),
|
||||
/// Migrate the delegation to use liquid tokens
|
||||
MigrateVestedDelegation(migrate_vested_delegation::Args),
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
|
||||
mix_id,
|
||||
amount,
|
||||
proxy,
|
||||
..
|
||||
} => {
|
||||
if owner.as_str() == client.nyxd.address().as_ref() {
|
||||
table.add_row(vec![
|
||||
@@ -112,7 +111,6 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
|
||||
owner,
|
||||
mix_id,
|
||||
proxy,
|
||||
..
|
||||
} => {
|
||||
if owner.as_str() == client.nyxd.address().as_ref() {
|
||||
table.add_row(vec![
|
||||
|
||||
+13
-2
@@ -8,7 +8,7 @@ use cosmwasm_std::Coin;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_mixnet_contract_common::construct_gateway_bonding_sign_payload;
|
||||
use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
@@ -39,6 +39,10 @@ pub struct Args {
|
||||
)]
|
||||
pub amount: u128,
|
||||
|
||||
/// Indicates whether the gateway is going to get bonded via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
@@ -70,8 +74,15 @@ pub async fn create_payload(args: Args, client: SigningClient) {
|
||||
};
|
||||
|
||||
let address = account_id_to_cw_addr(&client.address());
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(
|
||||
client.vesting_contract_address().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let payload = construct_gateway_bonding_sign_payload(nonce, address, coin, gateway);
|
||||
let payload = construct_gateway_bonding_sign_payload(nonce, address, proxy, coin, gateway);
|
||||
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
|
||||
println!("{}", args.output.format(&wrapper))
|
||||
}
|
||||
|
||||
@@ -5,21 +5,33 @@ use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Label that is going to be used for creating the family
|
||||
#[arg(long)]
|
||||
pub family_label: String,
|
||||
|
||||
/// Indicates whether the family is going to get created via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn create_family(args: Args, client: SigningClient) {
|
||||
info!("Create family");
|
||||
|
||||
let res = client
|
||||
.create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family");
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family")
|
||||
};
|
||||
|
||||
info!("Family creation result: {:?}", res);
|
||||
}
|
||||
|
||||
+16
-3
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::QueryClient;
|
||||
use crate::utils::DataWrapper;
|
||||
use crate::utils::{account_id_to_cw_addr, DataWrapper};
|
||||
use clap::Parser;
|
||||
use cosmrs::AccountId;
|
||||
use log::info;
|
||||
@@ -10,7 +10,7 @@ use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::construct_family_join_permit;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
@@ -18,6 +18,10 @@ pub struct Args {
|
||||
#[arg(long)]
|
||||
pub address: AccountId,
|
||||
|
||||
/// Indicates whether the member joining the family is going to use the vesting account for joining.
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
// might as well validate the value when parsing the arguments
|
||||
/// Identity of the member for whom we're issuing the permit
|
||||
#[arg(long)]
|
||||
@@ -64,9 +68,18 @@ pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryCli
|
||||
}
|
||||
};
|
||||
|
||||
// let address = account_id_to_cw_addr(&args.address);
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(
|
||||
client.vesting_contract_address().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let head = FamilyHead::new(mixnode.bond_information.identity());
|
||||
|
||||
let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string());
|
||||
let payload = construct_family_join_permit(nonce, head, proxy, args.member.to_base58_string());
|
||||
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
|
||||
println!("{}", args.output.format(&wrapper))
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
@@ -15,6 +16,10 @@ pub struct Args {
|
||||
#[arg(long)]
|
||||
pub family_head: identity::PublicKey,
|
||||
|
||||
/// Indicates whether the member joining the family is going to do so via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
/// Permission, as provided by the family head, for joining the family
|
||||
#[arg(long)]
|
||||
pub join_permit: MessageSignature,
|
||||
@@ -25,10 +30,17 @@ pub async fn join_family(args: Args, client: SigningClient) {
|
||||
|
||||
let family_head = FamilyHead::new(args.family_head.to_base58_string());
|
||||
|
||||
let res = client
|
||||
.join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family");
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family")
|
||||
};
|
||||
|
||||
info!("Family join result: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,17 @@ use log::info;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// The head of the family that we intend to leave
|
||||
#[arg(long)]
|
||||
pub family_head: identity::PublicKey,
|
||||
|
||||
/// Indicates whether we joined the family via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn leave_family(args: Args, client: SigningClient) {
|
||||
@@ -20,10 +25,17 @@ pub async fn leave_family(args: Args, client: SigningClient) {
|
||||
|
||||
let family_head = FamilyHead::new(args.family_head.to_base58_string());
|
||||
|
||||
let res = client
|
||||
.leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family");
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family")
|
||||
};
|
||||
|
||||
info!("Family leave result: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,7 @@ pub struct Args {
|
||||
}
|
||||
|
||||
pub fn decode_mixnode_key(args: Args) {
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
|
||||
let b64_decoded = STANDARD
|
||||
.decode(args.key)
|
||||
.expect("failed to decode base64 string");
|
||||
let b64_decoded = base64::decode(args.key).expect("failed to decode base64 string");
|
||||
let b58_encoded = bs58::encode(&b64_decoded).into_string();
|
||||
|
||||
println!("{b58_encoded}")
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {}
|
||||
|
||||
pub async fn migrate_vested_mixnode(_args: Args, client: SigningClient) {
|
||||
let res = client
|
||||
.migrate_vested_mixnode(None)
|
||||
.await
|
||||
.expect("failed to migrate mixnode!");
|
||||
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
+13
-2
@@ -11,7 +11,7 @@ use nym_mixnet_contract_common::{construct_mixnode_bonding_sign_payload, MixNode
|
||||
use nym_network_defaults::{
|
||||
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
|
||||
};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
|
||||
use nym_validator_client::nyxd::CosmWasmCoin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -52,6 +52,10 @@ pub struct Args {
|
||||
)]
|
||||
pub amount: u128,
|
||||
|
||||
/// Indicates whether the mixnode is going to get bonded via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
@@ -96,9 +100,16 @@ pub async fn create_payload(args: Args, client: SigningClient) {
|
||||
};
|
||||
|
||||
let address = account_id_to_cw_addr(&client.address());
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(
|
||||
client.vesting_contract_address().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let payload =
|
||||
construct_mixnode_bonding_sign_payload(nonce, address, coin, mixnode, cost_params);
|
||||
construct_mixnode_bonding_sign_payload(nonce, address, proxy, coin, mixnode, cost_params);
|
||||
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
|
||||
println!("{}", args.output.format(&wrapper))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ pub mod bond_mixnode;
|
||||
pub mod decrease_pledge;
|
||||
pub mod families;
|
||||
pub mod keys;
|
||||
pub mod migrate_vested_mixnode;
|
||||
pub mod mixnode_bonding_sign_payload;
|
||||
pub mod pledge_more;
|
||||
pub mod rewards;
|
||||
@@ -53,6 +52,4 @@ pub enum MixnetOperatorsMixnodeCommands {
|
||||
DecreasePledge(decrease_pledge::Args),
|
||||
/// Decrease pledge with locked tokens
|
||||
DecreasePledgeVesting(vesting_decrease_pledge::Args),
|
||||
/// Migrate the mixnode to use liquid tokens
|
||||
MigrateVestedNode(migrate_vested_mixnode::Args),
|
||||
}
|
||||
|
||||
@@ -218,6 +218,7 @@ where
|
||||
#[derive(Serialize)]
|
||||
pub struct ContractMessageContent<T> {
|
||||
pub sender: Addr,
|
||||
pub proxy: Option<Addr>,
|
||||
pub funds: Vec<Coin>,
|
||||
pub data: T,
|
||||
}
|
||||
@@ -232,17 +233,25 @@ where
|
||||
}
|
||||
|
||||
impl<T> ContractMessageContent<T> {
|
||||
pub fn new(sender: Addr, funds: Vec<Coin>, data: T) -> Self {
|
||||
pub fn new(sender: Addr, proxy: Option<Addr>, funds: Vec<Coin>, data: T) -> Self {
|
||||
ContractMessageContent {
|
||||
sender,
|
||||
proxy,
|
||||
funds,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_info(info: MessageInfo, signer: Addr, data: T) -> Self {
|
||||
let proxy = if info.sender == signer {
|
||||
None
|
||||
} else {
|
||||
Some(info.sender)
|
||||
};
|
||||
|
||||
ContractMessageContent {
|
||||
sender: signer,
|
||||
proxy,
|
||||
funds: info.funds,
|
||||
data,
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@ use cosmwasm_std::Coin;
|
||||
#[cw_serde]
|
||||
pub struct PoolCounters {
|
||||
pub total_deposited: Coin,
|
||||
pub total_redeemed: Coin,
|
||||
pub total_redeemed_gateways: Coin,
|
||||
pub total_redeemed_holding: Coin,
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ impl Delegation {
|
||||
cumulative_reward_ratio: Decimal,
|
||||
amount: Coin,
|
||||
height: u64,
|
||||
proxy: Option<Addr>,
|
||||
) -> Self {
|
||||
assert!(
|
||||
amount.amount <= TOKEN_SUPPLY,
|
||||
@@ -77,7 +78,7 @@ impl Delegation {
|
||||
cumulative_reward_ratio,
|
||||
amount,
|
||||
height,
|
||||
proxy: None,
|
||||
proxy,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, ProfitMarginRange};
|
||||
use crate::{EpochEventId, EpochState, IdentityKey, MixId};
|
||||
use contracts_common::signing::verifier::ApiVerifierError;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -77,11 +76,21 @@ pub enum MixnetContractError {
|
||||
#[error("Received multiple coin types during staking")]
|
||||
MultipleDenoms,
|
||||
|
||||
#[error("Proxy address mismatch, expected {existing}, got {incoming}")]
|
||||
ProxyMismatch { existing: String, incoming: String },
|
||||
|
||||
#[error("Proxy address ({received}) is not set to the vesting contract ({vesting_contract})")]
|
||||
ProxyIsNotVestingContract {
|
||||
received: Addr,
|
||||
vesting_contract: Addr,
|
||||
},
|
||||
#[error(
|
||||
"Sender of this message ({received}) is not the vesting contract ({vesting_contract})"
|
||||
)]
|
||||
SenderIsNotVestingContract {
|
||||
received: Addr,
|
||||
vesting_contract: Addr,
|
||||
},
|
||||
|
||||
#[error("Failed to recover ed25519 public key from its base58 representation - {0}")]
|
||||
MalformedEd25519IdentityKey(String),
|
||||
@@ -230,30 +239,6 @@ pub enum MixnetContractError {
|
||||
#[from]
|
||||
source: ApiVerifierError,
|
||||
},
|
||||
|
||||
#[error("this operation is no longer allowed to be performed with vesting tokens. please move them to your liquid balance and try again")]
|
||||
DisabledVestingOperation,
|
||||
|
||||
#[error(
|
||||
"this mixnode has not been bonded with the vesting tokens or has already been migrated"
|
||||
)]
|
||||
NotAVestingMixnode,
|
||||
|
||||
#[error("this delegation has not been performed with the vesting tokens or has already been migrated")]
|
||||
NotAVestingDelegation,
|
||||
|
||||
#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
|
||||
ProfitMarginOutsideRange {
|
||||
provided: Percent,
|
||||
range: ProfitMarginRange,
|
||||
},
|
||||
|
||||
#[error("the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}")]
|
||||
OperatingCostOutsideRange {
|
||||
denom: String,
|
||||
provided: Uint128,
|
||||
range: OperatingCostRange,
|
||||
},
|
||||
}
|
||||
|
||||
impl MixnetContractError {
|
||||
|
||||
@@ -103,6 +103,7 @@ impl Display for MixnetEventType {
|
||||
// attributes that are used in multiple places
|
||||
pub const OWNER_KEY: &str = "owner";
|
||||
pub const AMOUNT_KEY: &str = "amount";
|
||||
pub const PROXY_KEY: &str = "proxy";
|
||||
|
||||
// event-specific attributes
|
||||
|
||||
@@ -162,6 +163,7 @@ pub const NEW_EPOCHS_IN_INTERVAL: &str = "new_epochs_in_interval";
|
||||
pub fn new_delegation_event(
|
||||
created_at: BlockHeight,
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
mix_id: MixId,
|
||||
unit_reward: Decimal,
|
||||
@@ -169,34 +171,58 @@ pub fn new_delegation_event(
|
||||
Event::new(MixnetEventType::Delegation)
|
||||
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
.add_attribute(UNIT_REWARD_KEY, unit_reward.to_string())
|
||||
}
|
||||
|
||||
pub fn new_delegation_on_unbonded_node_event(delegator: &Addr, mix_id: MixId) -> Event {
|
||||
pub fn new_delegation_on_unbonded_node_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::Delegation)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_pending_delegation_event(delegator: &Addr, amount: &Coin, mix_id: MixId) -> Event {
|
||||
pub fn new_pending_delegation_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::PendingDelegation)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_withdraw_operator_reward_event(owner: &Addr, amount: Coin, mix_id: MixId) -> Event {
|
||||
pub fn new_withdraw_operator_reward_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: Coin,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::WithdrawOperatorReward)
|
||||
.add_attribute(OWNER_KEY, owner.as_str())
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_withdraw_delegator_reward_event(delegator: &Addr, amount: Coin, mix_id: MixId) -> Event {
|
||||
pub fn new_withdraw_delegator_reward_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: Coin,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::WithdrawDelegatorReward)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
|
||||
}
|
||||
@@ -252,43 +278,59 @@ pub fn new_pending_rewarding_params_update_event(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_undelegation_event(created_at: BlockHeight, delegator: &Addr, mix_id: MixId) -> Event {
|
||||
pub fn new_undelegation_event(
|
||||
created_at: BlockHeight,
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::Undelegation)
|
||||
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_pending_undelegation_event(delegator: &Addr, mix_id: MixId) -> Event {
|
||||
pub fn new_pending_undelegation_event(
|
||||
delegator: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::PendingUndelegation)
|
||||
.add_attribute(DELEGATOR_KEY, delegator)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
}
|
||||
|
||||
pub fn new_gateway_bonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::GatewayBonding)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
|
||||
pub fn new_gateway_unbonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::GatewayUnbonding)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
|
||||
pub fn new_mixnode_bonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
amount: &Coin,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
mix_id: MixId,
|
||||
@@ -299,6 +341,7 @@ pub fn new_mixnode_bonding_event(
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(ASSIGNED_LAYER_KEY, assigned_layer)
|
||||
.add_attribute(AMOUNT_KEY, amount.to_string())
|
||||
}
|
||||
@@ -337,6 +380,7 @@ pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Ev
|
||||
|
||||
pub fn new_pending_mixnode_unbonding_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
mix_id: MixId,
|
||||
) -> Event {
|
||||
@@ -344,33 +388,43 @@ pub fn new_pending_mixnode_unbonding_event(
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
}
|
||||
|
||||
pub fn new_mixnode_config_update_event(
|
||||
mix_id: MixId,
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
update: &MixNodeConfigUpdate,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::MixnodeConfigUpdate)
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(UPDATED_MIXNODE_CONFIG_KEY, update.to_inline_json())
|
||||
}
|
||||
|
||||
pub fn new_gateway_config_update_event(owner: &Addr, update: &GatewayConfigUpdate) -> Event {
|
||||
pub fn new_gateway_config_update_event(
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
update: &GatewayConfigUpdate,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::GatewayConfigUpdate)
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(UPDATED_GATEWAY_CONFIG_KEY, update.to_inline_json())
|
||||
}
|
||||
|
||||
pub fn new_mixnode_pending_cost_params_update_event(
|
||||
mix_id: MixId,
|
||||
owner: &Addr,
|
||||
proxy: &Option<Addr>,
|
||||
new_costs: &MixNodeCostParams,
|
||||
) -> Event {
|
||||
Event::new(MixnetEventType::PendingMixnodeCostParamsUpdate)
|
||||
.add_attribute(MIX_ID_KEY, mix_id.to_string())
|
||||
.add_attribute(OWNER_KEY, owner)
|
||||
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
|
||||
.add_attribute(UPDATED_MIXNODE_COST_PARAMS_KEY, new_costs.to_inline_json())
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::{IdentityKey, IdentityKeyRef};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Addr;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@@ -83,10 +84,10 @@ impl FamilyHead {
|
||||
}
|
||||
|
||||
impl Family {
|
||||
pub fn new(head: FamilyHead, label: String) -> Self {
|
||||
pub fn new(head: FamilyHead, proxy: Option<Addr>, label: String) -> Self {
|
||||
Family {
|
||||
head,
|
||||
proxy: None,
|
||||
proxy: proxy.map(|p| p.to_string()),
|
||||
label,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,13 +55,19 @@ pub struct GatewayBond {
|
||||
}
|
||||
|
||||
impl GatewayBond {
|
||||
pub fn new(pledge_amount: Coin, owner: Addr, block_height: u64, gateway: Gateway) -> Self {
|
||||
pub fn new(
|
||||
pledge_amount: Coin,
|
||||
owner: Addr,
|
||||
block_height: u64,
|
||||
gateway: Gateway,
|
||||
proxy: Option<Addr>,
|
||||
) -> Self {
|
||||
GatewayBond {
|
||||
pledge_amount,
|
||||
owner,
|
||||
block_height,
|
||||
gateway,
|
||||
proxy: None,
|
||||
proxy,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@ use crate::helpers::IntoBaseDecimal;
|
||||
use crate::reward_params::{NodeRewardParams, RewardingParams};
|
||||
use crate::rewarding::helpers::truncate_reward;
|
||||
use crate::rewarding::RewardDistribution;
|
||||
use crate::{
|
||||
Delegation, EpochEventId, EpochId, IdentityKey, MixId, OperatingCostRange, Percent,
|
||||
ProfitMarginRange, SphinxKey,
|
||||
};
|
||||
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
|
||||
use schemars::JsonSchema;
|
||||
@@ -155,16 +152,6 @@ impl MixNodeRewarding {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalise_profit_margin(&mut self, allowed_range: ProfitMarginRange) {
|
||||
self.cost_params.profit_margin_percent =
|
||||
allowed_range.normalise(self.cost_params.profit_margin_percent)
|
||||
}
|
||||
|
||||
pub fn normalise_operating_cost(&mut self, allowed_range: OperatingCostRange) {
|
||||
self.cost_params.interval_operating_cost.amount =
|
||||
allowed_range.normalise(self.cost_params.interval_operating_cost.amount)
|
||||
}
|
||||
|
||||
/// Determines whether this node is still bonded. This is performed via a simple check,
|
||||
/// if there are no tokens left associated with the operator, it means they have unbonded
|
||||
/// and those params only exist for the purposes of calculating rewards for delegators that
|
||||
@@ -531,6 +518,7 @@ impl MixNodeBond {
|
||||
original_pledge: Coin,
|
||||
layer: Layer,
|
||||
mix_node: MixNode,
|
||||
proxy: Option<Addr>,
|
||||
bonding_height: u64,
|
||||
) -> Self {
|
||||
MixNodeBond {
|
||||
@@ -539,7 +527,7 @@ impl MixNodeBond {
|
||||
original_pledge,
|
||||
layer,
|
||||
mix_node,
|
||||
proxy: None,
|
||||
proxy,
|
||||
bonding_height,
|
||||
is_unbonding: false,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::delegation::{self, OwnerProxySubKey};
|
||||
@@ -12,7 +12,6 @@ use crate::reward_params::{
|
||||
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
|
||||
};
|
||||
use crate::types::{ContractStateParams, LayerAssignment, MixId};
|
||||
use crate::{OperatingCostRange, ProfitMarginRange};
|
||||
use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Coin, Decimal};
|
||||
@@ -58,12 +57,6 @@ pub struct InstantiateMsg {
|
||||
pub epochs_in_interval: u32,
|
||||
pub epoch_duration: Duration,
|
||||
pub initial_rewarding_params: InitialRewardingParams,
|
||||
|
||||
#[serde(default)]
|
||||
pub profit_margin: ProfitMarginRange,
|
||||
|
||||
#[serde(default)]
|
||||
pub interval_operating_cost: OperatingCostRange,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
@@ -276,12 +269,6 @@ pub enum ExecuteMsg {
|
||||
owner: String,
|
||||
},
|
||||
|
||||
// vesting migration:
|
||||
MigrateVestedMixNode {},
|
||||
MigrateVestedDelegation {
|
||||
mix_id: MixId,
|
||||
},
|
||||
|
||||
// testing-only
|
||||
#[cfg(feature = "contract-testing")]
|
||||
TestingResolveAllPendingEvents {
|
||||
@@ -394,9 +381,6 @@ impl ExecuteMsg {
|
||||
ExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, .. } => {
|
||||
format!("withdrawing delegator reward from mixnode {mix_id} on behalf")
|
||||
}
|
||||
ExecuteMsg::MigrateVestedMixNode { .. } => "migrate vested mixnode".into(),
|
||||
ExecuteMsg::MigrateVestedDelegation { .. } => "migrate vested delegation".to_string(),
|
||||
|
||||
#[cfg(feature = "contract-testing")]
|
||||
ExecuteMsg::TestingResolveAllPendingEvents { .. } => {
|
||||
"resolving all pending events".into()
|
||||
|
||||
@@ -38,7 +38,6 @@ pub enum PendingEpochEventKind {
|
||||
/// Request to create a delegation towards particular mixnode.
|
||||
/// Note that if such delegation already exists, it will get updated with the provided token amount.
|
||||
#[serde(alias = "Delegate")]
|
||||
#[non_exhaustive]
|
||||
Delegate {
|
||||
/// The address of the owner of the delegation.
|
||||
owner: Addr,
|
||||
@@ -56,7 +55,6 @@ pub enum PendingEpochEventKind {
|
||||
|
||||
/// Request to remove delegation from particular mixnode.
|
||||
#[serde(alias = "Undelegate")]
|
||||
#[non_exhaustive]
|
||||
Undelegate {
|
||||
/// The address of the owner of the delegation.
|
||||
owner: Addr,
|
||||
@@ -111,23 +109,6 @@ impl PendingEpochEventKind {
|
||||
kind: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_delegate(owner: Addr, mix_id: MixId, amount: Coin) -> Self {
|
||||
PendingEpochEventKind::Delegate {
|
||||
owner,
|
||||
mix_id,
|
||||
amount,
|
||||
proxy: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_undelegate(owner: Addr, mix_id: MixId) -> Self {
|
||||
PendingEpochEventKind::Undelegate {
|
||||
owner,
|
||||
mix_id,
|
||||
proxy: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(EpochEventId, PendingEpochEventData)> for PendingEpochEvent {
|
||||
|
||||
+1
@@ -47,6 +47,7 @@ impl SimulatedNode {
|
||||
self.rewarding_details.total_unit_reward,
|
||||
delegation,
|
||||
42,
|
||||
None,
|
||||
);
|
||||
|
||||
self.delegations.insert(delegator, delegation);
|
||||
|
||||
@@ -37,12 +37,13 @@ impl SigningPurpose for MixnodeBondingPayload {
|
||||
pub fn construct_mixnode_bonding_sign_payload(
|
||||
nonce: Nonce,
|
||||
sender: Addr,
|
||||
proxy: Option<Addr>,
|
||||
pledge: Coin,
|
||||
mix_node: MixNode,
|
||||
cost_params: MixNodeCostParams,
|
||||
) -> SignableMixNodeBondingMsg {
|
||||
let payload = MixnodeBondingPayload::new(mix_node, cost_params);
|
||||
let content = ContractMessageContent::new(sender, vec![pledge], payload);
|
||||
let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);
|
||||
|
||||
SignableMessage::new(nonce, content)
|
||||
}
|
||||
@@ -67,11 +68,12 @@ impl SigningPurpose for GatewayBondingPayload {
|
||||
pub fn construct_gateway_bonding_sign_payload(
|
||||
nonce: Nonce,
|
||||
sender: Addr,
|
||||
proxy: Option<Addr>,
|
||||
pledge: Coin,
|
||||
gateway: Gateway,
|
||||
) -> SignableGatewayBondingMsg {
|
||||
let payload = GatewayBondingPayload::new(gateway);
|
||||
let content = ContractMessageContent::new(sender, vec![pledge], payload);
|
||||
let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);
|
||||
|
||||
SignableMessage::new(nonce, content)
|
||||
}
|
||||
@@ -80,14 +82,17 @@ pub fn construct_gateway_bonding_sign_payload(
|
||||
pub struct FamilyJoinPermit {
|
||||
// the granter of this permit
|
||||
family_head: FamilyHead,
|
||||
// whether the **member** will want to join via the proxy (i.e. vesting contract)
|
||||
proxy: Option<Addr>,
|
||||
// the actual member we want to permit to join
|
||||
member_node: IdentityKey,
|
||||
}
|
||||
|
||||
impl FamilyJoinPermit {
|
||||
pub fn new(family_head: FamilyHead, member_node: IdentityKey) -> Self {
|
||||
pub fn new(family_head: FamilyHead, proxy: Option<Addr>, member_node: IdentityKey) -> Self {
|
||||
Self {
|
||||
family_head,
|
||||
proxy,
|
||||
member_node,
|
||||
}
|
||||
}
|
||||
@@ -102,9 +107,10 @@ impl SigningPurpose for FamilyJoinPermit {
|
||||
pub fn construct_family_join_permit(
|
||||
nonce: Nonce,
|
||||
family_head: FamilyHead,
|
||||
proxy: Option<Addr>,
|
||||
member_node: IdentityKey,
|
||||
) -> SignableFamilyJoinPermitMsg {
|
||||
let payload = FamilyJoinPermit::new(family_head, member_node);
|
||||
let payload = FamilyJoinPermit::new(family_head, proxy, member_node);
|
||||
|
||||
// note: we're NOT wrapping it in `ContractMessageContent` because the family head is not going to be the one
|
||||
// sending the message to the contract
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
|
||||
use crate::error::MixnetContractError;
|
||||
use crate::Layer;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Addr;
|
||||
use cosmwasm_std::Coin;
|
||||
use cosmwasm_std::{Addr, Uint128};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Index;
|
||||
|
||||
// type aliases for better reasoning about available data
|
||||
@@ -17,65 +15,6 @@ pub type SphinxKeyRef<'a> = &'a str;
|
||||
pub type MixId = u32;
|
||||
pub type BlockHeight = u64;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RangedValue<T> {
|
||||
pub minimum: T,
|
||||
pub maximum: T,
|
||||
}
|
||||
|
||||
impl<T> Copy for RangedValue<T> where T: Copy {}
|
||||
|
||||
pub type ProfitMarginRange = RangedValue<Percent>;
|
||||
pub type OperatingCostRange = RangedValue<Uint128>;
|
||||
|
||||
impl<T> Display for RangedValue<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} - {}", self.minimum, self.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProfitMarginRange {
|
||||
fn default() -> Self {
|
||||
ProfitMarginRange {
|
||||
minimum: Percent::zero(),
|
||||
maximum: Percent::hundred(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OperatingCostRange {
|
||||
fn default() -> Self {
|
||||
OperatingCostRange {
|
||||
minimum: Uint128::zero(),
|
||||
|
||||
// 1 billion (native tokens, i.e. 1 billion * 1'000'000 base tokens) - the total supply
|
||||
maximum: Uint128::new(1_000_000_000_000_000),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangedValue<T>
|
||||
where
|
||||
T: Copy + PartialOrd + PartialEq,
|
||||
{
|
||||
pub fn normalise(&self, value: T) -> T {
|
||||
if value < self.minimum {
|
||||
self.minimum
|
||||
} else if value > self.maximum {
|
||||
self.maximum
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
pub fn within_range(&self, value: T) -> bool {
|
||||
value >= self.minimum && value <= self.maximum
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies layer assignment for the given mixnode.
|
||||
#[cw_serde]
|
||||
pub struct LayerAssignment {
|
||||
@@ -215,14 +154,4 @@ pub struct ContractStateParams {
|
||||
|
||||
/// Minimum amount a gateway must pledge to get into the system.
|
||||
pub minimum_gateway_pledge: Coin,
|
||||
|
||||
/// Defines the allowed profit margin range of operators.
|
||||
/// default: 0% - 100%
|
||||
#[serde(default)]
|
||||
pub profit_margin: ProfitMarginRange,
|
||||
|
||||
/// Defines the allowed interval operating cost range of operators.
|
||||
/// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)
|
||||
#[serde(default)]
|
||||
pub interval_operating_cost: OperatingCostRange,
|
||||
}
|
||||
|
||||
@@ -167,11 +167,3 @@ pub fn new_track_undelegation_event() -> Event {
|
||||
pub fn new_track_reward_event() -> Event {
|
||||
Event::new(TRACK_REWARD_EVENT_TYPE)
|
||||
}
|
||||
|
||||
pub fn new_track_migrate_mixnode_event() -> Event {
|
||||
Event::new("track_migrate_vesting_mixnode")
|
||||
}
|
||||
|
||||
pub fn new_track_migrate_delegation_event() -> Event {
|
||||
Event::new("track_migrate_vesting_delegation")
|
||||
}
|
||||
|
||||
@@ -136,14 +136,6 @@ pub enum ExecuteMsg {
|
||||
address: String,
|
||||
cap: PledgeCap,
|
||||
},
|
||||
TrackMigratedMixnode {
|
||||
owner: String,
|
||||
},
|
||||
// no need to track migrated gateways as there are no vesting gateways on mainnet
|
||||
TrackMigratedDelegation {
|
||||
owner: String,
|
||||
mix_id: MixId,
|
||||
},
|
||||
}
|
||||
|
||||
impl ExecuteMsg {
|
||||
@@ -179,10 +171,6 @@ impl ExecuteMsg {
|
||||
ExecuteMsg::TransferOwnership { .. } => "VestingExecuteMsg::TransferOwnership",
|
||||
ExecuteMsg::UpdateStakingAddress { .. } => "VestingExecuteMsg::UpdateStakingAddress",
|
||||
ExecuteMsg::UpdateLockedPledgeCap { .. } => "VestingExecuteMsg::UpdateLockedPledgeCap",
|
||||
ExecuteMsg::TrackMigratedMixnode { .. } => "VestingExecuteMsg::TrackMigratedMixnode",
|
||||
ExecuteMsg::TrackMigratedDelegation { .. } => {
|
||||
"VestingExecuteMsg::TrackMigratedDelegation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,6 @@ CREATE TABLE ecash_ticketbook
|
||||
-- introduce a way for us to introduce breaking changes in serialization of data
|
||||
serialization_revision INTEGER NOT NULL,
|
||||
|
||||
-- the type of the associated ticketbook
|
||||
ticketbook_type TEXT NOT NULL,
|
||||
|
||||
-- the actual crypto data of the ticketbook (wallet, keys, etc.)
|
||||
ticketbook_data BLOB NOT NULL UNIQUE,
|
||||
|
||||
|
||||
@@ -175,7 +175,6 @@ impl MemoryEcachTicketbookManager {
|
||||
.map(|t| BasicTicketbookInformation {
|
||||
id: t.ticketbook_id,
|
||||
expiration_date: t.ticketbook.expiration_date(),
|
||||
ticketbook_type: t.ticketbook.ticketbook_type().to_string(),
|
||||
epoch_id: t.ticketbook.epoch_id() as u32,
|
||||
total_tickets: t.ticketbook.spent_tickets() as u32,
|
||||
used_tickets: t.ticketbook.params_total_tickets() as u32,
|
||||
|
||||
@@ -61,13 +61,11 @@ impl SqliteEcashTicketbookManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn insert_new_ticketbook(
|
||||
&self,
|
||||
serialisation_revision: u8,
|
||||
data: &[u8],
|
||||
expiration_date: Date,
|
||||
typ: &str,
|
||||
epoch_id: u32,
|
||||
total_tickets: u32,
|
||||
used_tickets: u32,
|
||||
@@ -75,13 +73,12 @@ impl SqliteEcashTicketbookManager {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO ecash_ticketbook
|
||||
(serialization_revision, ticketbook_data, expiration_date, ticketbook_type, epoch_id, total_tickets, used_tickets)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
(serialization_revision, ticketbook_data, expiration_date, epoch_id, total_tickets, used_tickets)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
serialisation_revision,
|
||||
data,
|
||||
expiration_date,
|
||||
typ,
|
||||
epoch_id,
|
||||
total_tickets,
|
||||
used_tickets,
|
||||
@@ -95,7 +92,7 @@ impl SqliteEcashTicketbookManager {
|
||||
) -> Result<Vec<BasicTicketbookInformation>, sqlx::Error> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, expiration_date, ticketbook_type, epoch_id, total_tickets, used_tickets
|
||||
SELECT id, expiration_date, epoch_id, total_tickets, used_tickets
|
||||
FROM ecash_ticketbook
|
||||
"#,
|
||||
)
|
||||
|
||||
@@ -19,7 +19,6 @@ pub struct RetrievedPendingTicketbook {
|
||||
pub struct BasicTicketbookInformation {
|
||||
pub id: i64,
|
||||
pub expiration_date: Date,
|
||||
pub ticketbook_type: String,
|
||||
pub epoch_id: u32,
|
||||
pub total_tickets: u32,
|
||||
pub used_tickets: u32,
|
||||
@@ -32,8 +31,6 @@ pub struct StoredIssuedTicketbook {
|
||||
|
||||
pub serialization_revision: u8,
|
||||
|
||||
pub ticketbook_type: String,
|
||||
|
||||
pub ticketbook_data: Vec<u8>,
|
||||
|
||||
#[zeroize(skip)]
|
||||
|
||||
@@ -114,7 +114,6 @@ impl Storage for PersistentStorage {
|
||||
serialisation_revision,
|
||||
&data,
|
||||
ticketbook.expiration_date(),
|
||||
&ticketbook.ticketbook_type().to_string(),
|
||||
ticketbook.epoch_id() as u32,
|
||||
ticketbook.params_total_tickets() as u32,
|
||||
ticketbook.spent_tickets() as u32,
|
||||
|
||||
@@ -14,9 +14,9 @@ time.workspace = true
|
||||
|
||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credentials-interface = { path = "../../common/credentials-interface" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage", features = ["persistent-storage"] }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-client-core = { path = "../../common/client-core" }
|
||||
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" }
|
||||
nym-ecash-time = { path = "../../common/ecash-time" }
|
||||
@@ -1,14 +1,12 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::errors::{Error, Result};
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::acquire::{get_ticket_book, query_and_persist_required_global_data};
|
||||
use nym_bandwidth_controller::acquire::{
|
||||
get_ticket_book, query_and_persist_required_global_signatures,
|
||||
};
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use nym_config::DEFAULT_DATA_DIR;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_ecash_time::ecash_default_expiration_date;
|
||||
use nym_validator_client::coconut::all_ecash_api_clients;
|
||||
use nym_validator_client::nyxd::contract_traits::{
|
||||
@@ -18,12 +16,7 @@ use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub async fn issue_credential<C, S>(
|
||||
client: &C,
|
||||
storage: &S,
|
||||
client_id: &[u8],
|
||||
typ: TicketType,
|
||||
) -> Result<()>
|
||||
pub async fn issue_credential<C, S>(client: &C, storage: &S, client_id: &[u8]) -> Result<()>
|
||||
where
|
||||
C: DkgQueryClient + EcashSigningClient + EcashQueryClient + Send + Sync,
|
||||
S: Storage,
|
||||
@@ -43,16 +36,19 @@ where
|
||||
let apis = all_ecash_api_clients(client, epoch_id).await?;
|
||||
let ticketbook_expiration = ecash_default_expiration_date();
|
||||
|
||||
// make sure we have all required coin indices and expiration date signatures alongside the master verification key
|
||||
// before attempting the deposit
|
||||
query_and_persist_required_global_data(storage, epoch_id, ticketbook_expiration, apis.clone())
|
||||
.await?;
|
||||
// make sure we have all required coin indices and expiration date signatures before attempting the deposit
|
||||
query_and_persist_required_global_signatures(
|
||||
storage,
|
||||
epoch_id,
|
||||
ticketbook_expiration,
|
||||
apis.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let issuance_data = nym_bandwidth_controller::acquire::make_deposit(
|
||||
client,
|
||||
client_id,
|
||||
Some(ticketbook_expiration),
|
||||
typ,
|
||||
)
|
||||
.await?;
|
||||
info!("Deposit done");
|
||||
@@ -69,7 +65,7 @@ where
|
||||
}).map_err(Error::storage_error)?
|
||||
}
|
||||
|
||||
info!("Succeeded adding a ticketbook of type '{typ}'");
|
||||
info!("Succeeded adding a ticketbook");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -14,10 +14,8 @@ license.workspace = true
|
||||
bls12_381 = { workspace = true, default-features = false }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true, features = ["serde"] }
|
||||
rand = { workspace = true }
|
||||
|
||||
nym-compact-ecash = { path = "../nym_offline_compact_ecash" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_network_defaults::TicketTypeRepr;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use time::{Date, OffsetDateTime};
|
||||
|
||||
pub use nym_compact_ecash::{
|
||||
@@ -17,6 +15,7 @@ pub use nym_compact_ecash::{
|
||||
PartialCoinIndexSignature,
|
||||
},
|
||||
scheme::expiration_date_signatures::aggregate_expiration_signatures,
|
||||
scheme::expiration_date_signatures::date_scalar,
|
||||
scheme::expiration_date_signatures::{
|
||||
AnnotatedExpirationDateSignature, ExpirationDateSignature, ExpirationDateSignatureShare,
|
||||
PartialExpirationDateSignature,
|
||||
@@ -25,10 +24,10 @@ pub use nym_compact_ecash::{
|
||||
scheme::withdrawal::RequestInfo,
|
||||
scheme::Payment,
|
||||
scheme::{Wallet, WalletSignatures},
|
||||
withdrawal_request, Base58, BlindedSignature, Bytable, EncodedDate, EncodedTicketType,
|
||||
PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
|
||||
withdrawal_request, Base58, BlindedSignature, Bytable, PartialWallet, PayInfo, PublicKeyUser,
|
||||
SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
|
||||
};
|
||||
use nym_ecash_time::{ecash_today, EcashTime};
|
||||
use nym_ecash_time::EcashTime;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CredentialSigningData {
|
||||
@@ -39,8 +38,6 @@ pub struct CredentialSigningData {
|
||||
pub ecash_pub_key: PublicKeyUser,
|
||||
|
||||
pub expiration_date: Date,
|
||||
|
||||
pub ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
@@ -61,7 +58,7 @@ impl CredentialSpendingData {
|
||||
self.payment.spend_verify(
|
||||
verification_key,
|
||||
&self.pay_info,
|
||||
self.spend_date.ecash_unix_timestamp(),
|
||||
date_scalar(self.spend_date.ecash_unix_timestamp()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -219,112 +216,3 @@ impl From<PayInfo> for NymPayInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
strum::Display,
|
||||
strum::EnumString,
|
||||
)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum TicketType {
|
||||
#[default]
|
||||
V1MixnetEntry,
|
||||
V1MixnetExit,
|
||||
V1WireguardEntry,
|
||||
V1WireguardExit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Error)]
|
||||
#[error("provided unknown ticketbook type")]
|
||||
pub struct UnknownTicketType;
|
||||
|
||||
impl TicketType {
|
||||
pub fn to_repr(&self) -> TicketTypeRepr {
|
||||
(*self).into()
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> EncodedTicketType {
|
||||
self.to_repr() as EncodedTicketType
|
||||
}
|
||||
|
||||
pub fn try_from_encoded(val: EncodedTicketType) -> Result<Self, UnknownTicketType> {
|
||||
match val {
|
||||
n if n == TicketTypeRepr::V1MixnetEntry as u8 => {
|
||||
Ok(TicketTypeRepr::V1MixnetEntry.into())
|
||||
}
|
||||
n if n == TicketTypeRepr::V1MixnetExit as u8 => Ok(TicketTypeRepr::V1MixnetExit.into()),
|
||||
n if n == TicketTypeRepr::V1WireguardEntry as u8 => {
|
||||
Ok(TicketTypeRepr::V1WireguardEntry.into())
|
||||
}
|
||||
n if n == TicketTypeRepr::V1WireguardExit as u8 => {
|
||||
Ok(TicketTypeRepr::V1WireguardExit.into())
|
||||
}
|
||||
_ => Err(UnknownTicketType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TicketType> for TicketTypeRepr {
|
||||
fn from(value: TicketType) -> Self {
|
||||
match value {
|
||||
TicketType::V1MixnetEntry => TicketTypeRepr::V1MixnetEntry,
|
||||
TicketType::V1MixnetExit => TicketTypeRepr::V1MixnetExit,
|
||||
TicketType::V1WireguardEntry => TicketTypeRepr::V1WireguardEntry,
|
||||
TicketType::V1WireguardExit => TicketTypeRepr::V1WireguardExit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TicketTypeRepr> for TicketType {
|
||||
fn from(value: TicketTypeRepr) -> Self {
|
||||
match value {
|
||||
TicketTypeRepr::V1MixnetEntry => TicketType::V1MixnetEntry,
|
||||
TicketTypeRepr::V1MixnetExit => TicketType::V1MixnetExit,
|
||||
TicketTypeRepr::V1WireguardEntry => TicketType::V1WireguardEntry,
|
||||
TicketTypeRepr::V1WireguardExit => TicketType::V1WireguardExit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientTicket {
|
||||
pub spending_data: CredentialSpendingData,
|
||||
pub ticket_id: i64,
|
||||
}
|
||||
|
||||
impl ClientTicket {
|
||||
pub fn new(spending_data: CredentialSpendingData, ticket_id: i64) -> Self {
|
||||
ClientTicket {
|
||||
spending_data,
|
||||
ticket_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct AvailableBandwidth {
|
||||
pub bytes: i64,
|
||||
pub expiration: OffsetDateTime,
|
||||
}
|
||||
|
||||
impl AvailableBandwidth {
|
||||
pub fn expired(&self) -> bool {
|
||||
self.expiration < ecash_today()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AvailableBandwidth {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bytes: 0,
|
||||
expiration: OffsetDateTime::UNIX_EPOCH,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::ecash::bandwidth::issued::IssuedTicketBook;
|
||||
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
|
||||
use crate::ecash::bandwidth::CredentialSigningData;
|
||||
use crate::ecash::utils::cred_exp_date;
|
||||
use crate::error::Error;
|
||||
use nym_api_requests::ecash::BlindSignRequestBody;
|
||||
use nym_credentials_interface::{
|
||||
aggregate_wallets, generate_keypair_user_from_seed, issue_verify, withdrawal_request,
|
||||
BlindedSignature, KeyPairUser, PartialWallet, TicketType, VerificationKeyAuth,
|
||||
WalletSignatures, WithdrawalRequest,
|
||||
BlindedSignature, KeyPairUser, PartialWallet, VerificationKeyAuth, WalletSignatures,
|
||||
WithdrawalRequest,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_ecash_contract_common::deposit::DepositId;
|
||||
@@ -19,6 +18,7 @@ use nym_validator_client::nym_api::EpochId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::Date;
|
||||
|
||||
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
|
||||
pub use nym_validator_client::nyxd::{Coin, Hash};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -32,9 +32,6 @@ pub struct IssuanceTicketBook {
|
||||
/// ecash keypair related to the credential
|
||||
ecash_keypair: KeyPairUser,
|
||||
|
||||
/// the type of the ticketbook to be issued
|
||||
ticketbook_type: TicketType,
|
||||
|
||||
/// expiration_date of that credential
|
||||
expiration_date: Date,
|
||||
}
|
||||
@@ -44,14 +41,12 @@ impl IssuanceTicketBook {
|
||||
deposit_id: DepositId,
|
||||
identifier: M,
|
||||
signing_key: identity::PrivateKey,
|
||||
ticketbook_type: TicketType,
|
||||
) -> Self {
|
||||
//this expiration date will get fed to the ecash library, force midnight to be set
|
||||
Self::new_with_expiration(
|
||||
deposit_id,
|
||||
identifier,
|
||||
signing_key,
|
||||
ticketbook_type,
|
||||
ecash_default_expiration_date(),
|
||||
)
|
||||
}
|
||||
@@ -60,7 +55,6 @@ impl IssuanceTicketBook {
|
||||
deposit_id: DepositId,
|
||||
identifier: M,
|
||||
signing_key: identity::PrivateKey,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
) -> Self {
|
||||
let ecash_keypair = generate_keypair_user_from_seed(identifier);
|
||||
@@ -68,7 +62,6 @@ impl IssuanceTicketBook {
|
||||
deposit_id,
|
||||
signing_key,
|
||||
ecash_keypair,
|
||||
ticketbook_type,
|
||||
expiration_date,
|
||||
}
|
||||
}
|
||||
@@ -83,10 +76,6 @@ impl IssuanceTicketBook {
|
||||
self.expiration_date
|
||||
}
|
||||
|
||||
pub fn ticketbook_type(&self) -> TicketType {
|
||||
self.ticketbook_type
|
||||
}
|
||||
|
||||
pub fn request_plaintext(request: &WithdrawalRequest, deposit_id: DepositId) -> Vec<u8> {
|
||||
let mut message = request.to_bytes();
|
||||
message.extend_from_slice(&deposit_id.to_be_bytes());
|
||||
@@ -110,7 +99,6 @@ impl IssuanceTicketBook {
|
||||
request_signature,
|
||||
signing_request.ecash_pub_key.clone(),
|
||||
signing_request.expiration_date,
|
||||
signing_request.ticketbook_type,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -145,7 +133,6 @@ impl IssuanceTicketBook {
|
||||
let (withdrawal_request, request_info) = withdrawal_request(
|
||||
self.ecash_keypair.secret_key(),
|
||||
self.expiration_date.ecash_unix_timestamp(),
|
||||
self.ticketbook_type.encode(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -154,7 +141,6 @@ impl IssuanceTicketBook {
|
||||
request_info,
|
||||
ecash_pub_key: self.ecash_keypair.public_key(),
|
||||
expiration_date: self.expiration_date,
|
||||
ticketbook_type: self.ticketbook_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +218,6 @@ impl IssuanceTicketBook {
|
||||
wallet,
|
||||
epoch_id,
|
||||
self.ecash_keypair.secret_key().clone(),
|
||||
self.ticketbook_type,
|
||||
self.expiration_date,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::ecash::bandwidth::CredentialSpendingData;
|
||||
use crate::ecash::utils::ecash_today;
|
||||
use crate::error::Error;
|
||||
use nym_credentials_interface::{
|
||||
CoinIndexSignature, ExpirationDateSignature, NymPayInfo, PayInfo, SecretKeyUser, TicketType,
|
||||
VerificationKeyAuth, Wallet, WalletSignatures,
|
||||
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, VerificationKeyAuth,
|
||||
Wallet, WalletSignatures,
|
||||
};
|
||||
use nym_ecash_time::EcashTime;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -36,10 +36,6 @@ pub struct IssuedTicketBook {
|
||||
/// expiration_date for easier discarding
|
||||
#[zeroize(skip)]
|
||||
expiration_date: Date,
|
||||
|
||||
/// the type of the ticketbook to got issued
|
||||
#[zeroize(skip)]
|
||||
ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
impl IssuedTicketBook {
|
||||
@@ -47,7 +43,6 @@ impl IssuedTicketBook {
|
||||
wallet: WalletSignatures,
|
||||
epoch_id: EpochId,
|
||||
ecash_secret_key: SecretKeyUser,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
) -> Self {
|
||||
IssuedTicketBook {
|
||||
@@ -56,7 +51,6 @@ impl IssuedTicketBook {
|
||||
epoch_id,
|
||||
ecash_secret_key,
|
||||
expiration_date,
|
||||
ticketbook_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +58,6 @@ impl IssuedTicketBook {
|
||||
signatures_wallet: WalletSignatures,
|
||||
epoch_id: EpochId,
|
||||
ecash_secret_key: SecretKeyUser,
|
||||
ticketbook_type: TicketType,
|
||||
expiration_date: Date,
|
||||
spent_tickets: u64,
|
||||
) -> Self {
|
||||
@@ -74,7 +67,6 @@ impl IssuedTicketBook {
|
||||
epoch_id,
|
||||
ecash_secret_key,
|
||||
expiration_date,
|
||||
ticketbook_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,10 +78,6 @@ impl IssuedTicketBook {
|
||||
self.epoch_id
|
||||
}
|
||||
|
||||
pub fn ticketbook_type(&self) -> TicketType {
|
||||
self.ticketbook_type
|
||||
}
|
||||
|
||||
pub fn current_serialization_revision(&self) -> u8 {
|
||||
CURRENT_SERIALIZATION_REVISION
|
||||
}
|
||||
@@ -114,10 +102,6 @@ impl IssuedTicketBook {
|
||||
&self.signatures_wallet
|
||||
}
|
||||
|
||||
pub fn generate_pay_info(&self, provider_pk: [u8; 32]) -> NymPayInfo {
|
||||
NymPayInfo::generate(provider_pk)
|
||||
}
|
||||
|
||||
pub fn prepare_for_spending<BI, BE>(
|
||||
&mut self,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
|
||||
@@ -36,6 +36,22 @@ pub fn aggregate_verification_keys(
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn obtain_aggregated_verification_key(
|
||||
_api_clients: &[EcashApiClient],
|
||||
) -> Result<VerificationKeyAuth, Error> {
|
||||
// TODO:
|
||||
// let total = api_clients.len();
|
||||
// let mut rng = thread_rng();
|
||||
// let indices = sample(&mut rng, total, total);
|
||||
// for index in indices {
|
||||
// // randomly try apis until we succeed
|
||||
// // if let Ok(res) = api_clients[index].api_client.get_aggregated_verification_key().await {
|
||||
// // //
|
||||
// // }
|
||||
// }
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn obtain_expiration_date_signatures(
|
||||
ecash_api_clients: &[EcashApiClient],
|
||||
verification_key: &VerificationKeyAuth,
|
||||
@@ -47,7 +63,7 @@ pub async fn obtain_expiration_date_signatures(
|
||||
|
||||
let mut signatures_shares: Vec<_> = Vec::with_capacity(ecash_api_clients.len());
|
||||
|
||||
let expiration_date = cred_exp_date().ecash_unix_timestamp();
|
||||
let expiration_date = cred_exp_date().unix_timestamp() as u64;
|
||||
for ecash_api_client in ecash_api_clients.iter() {
|
||||
match ecash_api_client
|
||||
.api_client
|
||||
|
||||
@@ -6,16 +6,13 @@ use time::{Duration, PrimitiveDateTime, Time};
|
||||
pub use time::{Date, OffsetDateTime};
|
||||
|
||||
pub trait EcashTime {
|
||||
fn ecash_unix_timestamp(&self) -> u32 {
|
||||
fn ecash_unix_timestamp(&self) -> u64 {
|
||||
let ts = self.ecash_datetime().unix_timestamp();
|
||||
|
||||
// just panic on pre-1970 timestamps...
|
||||
assert!(ts > 0);
|
||||
|
||||
// and on anything in 22nd century...
|
||||
assert!(ts <= u32::MAX as i64);
|
||||
|
||||
ts as u32
|
||||
ts as u64
|
||||
}
|
||||
|
||||
fn ecash_date(&self) -> Date {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
[package]
|
||||
name = "nym-gateway-storage"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
bincode = { workspace = true, optional = true }
|
||||
defguard_wireguard_rs = { workspace = true, optional = true }
|
||||
log = { workspace = true }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
"time",
|
||||
] }
|
||||
time = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
nym-gateway-requests = { path = "../gateway-requests" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
|
||||
[features]
|
||||
wireguard = ["defguard_wireguard_rs", "bincode"]
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
CREATE TABLE wireguard_peer
|
||||
(
|
||||
public_key TEXT NOT NULL PRIMARY KEY UNIQUE,
|
||||
preshared_key TEXT,
|
||||
protocol_version INTEGER,
|
||||
endpoint TEXT,
|
||||
last_handshake TIMESTAMP,
|
||||
tx_bytes BIGINT NOT NULL,
|
||||
rx_bytes BIGINT NOT NULL,
|
||||
persistent_keepalive_interval INTEGER,
|
||||
allowed_ips BLOB NOT NULL,
|
||||
suspended BOOLEAN NOT NULL
|
||||
);
|
||||
@@ -1,182 +0,0 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::error::StorageError;
|
||||
use nym_credentials_interface::{AvailableBandwidth, ClientTicket, CredentialSpendingData};
|
||||
use sqlx::FromRow;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub struct PersistedSharedKeys {
|
||||
#[allow(dead_code)]
|
||||
pub id: i64,
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub client_address_bs58: String,
|
||||
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
|
||||
}
|
||||
|
||||
pub struct StoredMessage {
|
||||
pub id: i64,
|
||||
#[allow(dead_code)]
|
||||
pub client_address_bs58: String,
|
||||
pub content: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
pub struct PersistedBandwidth {
|
||||
#[allow(dead_code)]
|
||||
pub client_id: i64,
|
||||
pub available: i64,
|
||||
pub expiration: Option<OffsetDateTime>,
|
||||
}
|
||||
|
||||
impl From<PersistedBandwidth> for AvailableBandwidth {
|
||||
fn from(value: PersistedBandwidth) -> Self {
|
||||
AvailableBandwidth {
|
||||
bytes: value.available,
|
||||
expiration: value.expiration.unwrap_or(OffsetDateTime::UNIX_EPOCH),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct VerifiedTicket {
|
||||
pub serial_number: Vec<u8>,
|
||||
pub ticket_id: i64,
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct RedemptionProposal {
|
||||
pub proposal_id: i64,
|
||||
pub created_at: OffsetDateTime,
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct UnverifiedTicketData {
|
||||
pub data: Vec<u8>,
|
||||
pub ticket_id: i64,
|
||||
}
|
||||
|
||||
impl TryFrom<UnverifiedTicketData> for ClientTicket {
|
||||
type Error = StorageError;
|
||||
|
||||
fn try_from(value: UnverifiedTicketData) -> Result<Self, Self::Error> {
|
||||
Ok(ClientTicket {
|
||||
spending_data: CredentialSpendingData::try_from_bytes(&value.data).map_err(|_| {
|
||||
StorageError::MalformedStoredTicketData {
|
||||
ticket_id: value.ticket_id,
|
||||
}
|
||||
})?,
|
||||
ticket_id: value.ticket_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
pub struct WireguardPeer {
|
||||
pub public_key: String,
|
||||
pub preshared_key: Option<String>,
|
||||
pub protocol_version: Option<i64>,
|
||||
pub endpoint: Option<String>,
|
||||
pub last_handshake: Option<sqlx::types::chrono::NaiveDateTime>,
|
||||
pub tx_bytes: i64,
|
||||
pub rx_bytes: i64,
|
||||
pub persistent_keepalive_interval: Option<i64>,
|
||||
pub allowed_ips: Vec<u8>,
|
||||
pub suspended: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
impl From<defguard_wireguard_rs::host::Peer> for WireguardPeer {
|
||||
fn from(value: defguard_wireguard_rs::host::Peer) -> Self {
|
||||
WireguardPeer {
|
||||
public_key: value.public_key.to_string(),
|
||||
preshared_key: value.preshared_key.as_ref().map(|k| k.to_string()),
|
||||
protocol_version: value.protocol_version.map(|v| v as i64),
|
||||
endpoint: value.endpoint.map(|e| e.to_string()),
|
||||
last_handshake: value.last_handshake.and_then(|t| {
|
||||
if let Ok(d) = t.duration_since(std::time::UNIX_EPOCH) {
|
||||
if let Ok(millis) = d.as_millis().try_into() {
|
||||
sqlx::types::chrono::DateTime::from_timestamp_millis(millis)
|
||||
.map(|d| d.naive_utc())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
tx_bytes: value.tx_bytes as i64,
|
||||
rx_bytes: value.rx_bytes as i64,
|
||||
persistent_keepalive_interval: value.persistent_keepalive_interval.map(|v| v as i64),
|
||||
allowed_ips: bincode::Options::serialize(
|
||||
bincode::DefaultOptions::new(),
|
||||
&value.allowed_ips,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
suspended: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
impl TryFrom<WireguardPeer> for defguard_wireguard_rs::host::Peer {
|
||||
type Error = crate::error::StorageError;
|
||||
|
||||
fn try_from(value: WireguardPeer) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
public_key: value
|
||||
.public_key
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("public key {e}")))?,
|
||||
preshared_key: value
|
||||
.preshared_key
|
||||
.as_deref()
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("preshared key {e}")))?,
|
||||
protocol_version: value
|
||||
.protocol_version
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("protocol version {e}")))?,
|
||||
endpoint: value
|
||||
.endpoint
|
||||
.as_deref()
|
||||
.map(|e| e.parse())
|
||||
.transpose()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("endpoint {e}")))?,
|
||||
last_handshake: value.last_handshake.and_then(|t| {
|
||||
let unix_time = std::time::UNIX_EPOCH;
|
||||
if let Ok(millis) = t.and_utc().timestamp_millis().try_into() {
|
||||
let duration = std::time::Duration::from_millis(millis);
|
||||
unix_time.checked_add(duration)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
tx_bytes: value
|
||||
.tx_bytes
|
||||
.try_into()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("tx bytes {e}")))?,
|
||||
rx_bytes: value
|
||||
.rx_bytes
|
||||
.try_into()
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("rx bytes {e}")))?,
|
||||
persistent_keepalive_interval: value
|
||||
.persistent_keepalive_interval
|
||||
.map(TryFrom::try_from)
|
||||
.transpose()
|
||||
.map_err(|e| {
|
||||
Self::Error::TypeConversion(format!("persistent keepalive interval {e}"))
|
||||
})?,
|
||||
allowed_ips: bincode::Options::deserialize(
|
||||
bincode::DefaultOptions::new(),
|
||||
&value.allowed_ips,
|
||||
)
|
||||
.map_err(|e| Self::Error::TypeConversion(format!("allowed ips {e}")))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::models::WireguardPeer;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct WgPeerManager {
|
||||
connection_pool: sqlx::SqlitePool,
|
||||
}
|
||||
|
||||
impl WgPeerManager {
|
||||
/// Creates new instance of the `WgPeersManager` with the provided sqlite connection pool.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `connection_pool`: database connection pool to use.
|
||||
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
||||
WgPeerManager { connection_pool }
|
||||
}
|
||||
|
||||
/// Creates a new wireguard peer entry for its particular public key or
|
||||
/// overwrittes the peer entry data if it already existed.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer`: peer information needed by wireguard interface.
|
||||
pub(crate) async fn insert_peer(&self, peer: &WireguardPeer) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"INSERT OR REPLACE INTO wireguard_peer(public_key, preshared_key, protocol_version, endpoint, last_handshake, tx_bytes, rx_bytes, persistent_keepalive_interval, allowed_ips, suspended) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
peer.public_key, peer.preshared_key, peer.protocol_version, peer.endpoint, peer.last_handshake, peer.tx_bytes, peer.rx_bytes, peer.persistent_keepalive_interval, peer.allowed_ips, peer.suspended
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve the wireguard peer with the provided public key from the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `public_key`: the unique public key of the wireguard peer.
|
||||
pub(crate) async fn retrieve_peer(
|
||||
&self,
|
||||
public_key: &str,
|
||||
) -> Result<Option<WireguardPeer>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
WireguardPeer,
|
||||
r#"
|
||||
SELECT * FROM wireguard_peer
|
||||
WHERE public_key = ?
|
||||
LIMIT 1
|
||||
"#,
|
||||
public_key,
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Retrieve all wireguard peers.
|
||||
pub(crate) async fn retrieve_all_peers(&self) -> Result<Vec<WireguardPeer>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
WireguardPeer,
|
||||
r#"
|
||||
SELECT *
|
||||
FROM wireguard_peer;
|
||||
"#,
|
||||
)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Retrieve the wireguard peer with the provided public key from the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `public_key`: the unique public key of the wireguard peer.
|
||||
pub(crate) async fn remove_peer(&self, public_key: &str) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
DELETE FROM wireguard_peer
|
||||
WHERE public_key = ?
|
||||
"#,
|
||||
public_key,
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{v6, v7};
|
||||
|
||||
impl From<v7::response::StaticConnectFailureReason> for v6::response::StaticConnectFailureReason {
|
||||
fn from(failure: v7::response::StaticConnectFailureReason) -> Self {
|
||||
match failure {
|
||||
v7::response::StaticConnectFailureReason::RequestedIpAlreadyInUse => {
|
||||
v6::response::StaticConnectFailureReason::RequestedIpAlreadyInUse
|
||||
}
|
||||
v7::response::StaticConnectFailureReason::RequestedNymAddressAlreadyInUse => {
|
||||
v6::response::StaticConnectFailureReason::RequestedNymAddressAlreadyInUse
|
||||
}
|
||||
v7::response::StaticConnectFailureReason::OutOfDateTimestamp => {
|
||||
v6::response::StaticConnectFailureReason::Other("out of date timestamp".to_string())
|
||||
}
|
||||
v7::response::StaticConnectFailureReason::Other(reason) => {
|
||||
v6::response::StaticConnectFailureReason::Other(reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v7::response::DynamicConnectFailureReason> for v6::response::DynamicConnectFailureReason {
|
||||
fn from(failure: v7::response::DynamicConnectFailureReason) -> Self {
|
||||
match failure {
|
||||
v7::response::DynamicConnectFailureReason::RequestedNymAddressAlreadyInUse => {
|
||||
v6::response::DynamicConnectFailureReason::RequestedNymAddressAlreadyInUse
|
||||
}
|
||||
v7::response::DynamicConnectFailureReason::NoAvailableIp => {
|
||||
v6::response::DynamicConnectFailureReason::NoAvailableIp
|
||||
}
|
||||
v7::response::DynamicConnectFailureReason::Other(err) => {
|
||||
v6::response::DynamicConnectFailureReason::Other(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v7::response::InfoResponseReply> for v6::response::InfoResponseReply {
|
||||
fn from(reply: v7::response::InfoResponseReply) -> Self {
|
||||
match reply {
|
||||
v7::response::InfoResponseReply::Generic { msg } => {
|
||||
v6::response::InfoResponseReply::Generic { msg }
|
||||
}
|
||||
v7::response::InfoResponseReply::VersionMismatch {
|
||||
request_version,
|
||||
response_version,
|
||||
} => v6::response::InfoResponseReply::VersionMismatch {
|
||||
request_version,
|
||||
response_version,
|
||||
},
|
||||
v7::response::InfoResponseReply::ExitPolicyFilterCheckFailed { dst } => {
|
||||
v6::response::InfoResponseReply::ExitPolicyFilterCheckFailed { dst }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v7::response::InfoLevel> for v6::response::InfoLevel {
|
||||
fn from(level: v7::response::InfoLevel) -> Self {
|
||||
match level {
|
||||
v7::response::InfoLevel::Info => v6::response::InfoLevel::Info,
|
||||
v7::response::InfoLevel::Warn => v6::response::InfoLevel::Warn,
|
||||
v7::response::InfoLevel::Error => v6::response::InfoLevel::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod conversion;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
||||
|
||||
@@ -198,17 +198,6 @@ impl IpPacketRequestData {
|
||||
| IpPacketRequestData::Health(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signable_request(&self) -> Option<Result<Vec<u8>, SignatureError>> {
|
||||
match self {
|
||||
IpPacketRequestData::StaticConnect(request) => Some(request.request()),
|
||||
IpPacketRequestData::DynamicConnect(request) => Some(request.request()),
|
||||
IpPacketRequestData::Disconnect(request) => Some(request.request()),
|
||||
IpPacketRequestData::Data(_) => None,
|
||||
IpPacketRequestData::Ping(_) => None,
|
||||
IpPacketRequestData::Health(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A static connect request is when the client provides the internal IP address it will use on the
|
||||
|
||||
@@ -7,7 +7,7 @@ license.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bip32 = { workspace = true, features = ["secp256k1", "std"] }
|
||||
bip32 = { workspace = true }
|
||||
k256 = { workspace = true }
|
||||
ledger-transport = { workspace = true }
|
||||
ledger-transport-hid = { workspace = true }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "nym-mobile-storage"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -2,24 +2,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/// Specifies the maximum validity of the issued ticketbooks.
|
||||
pub const TICKETBOOK_VALIDITY_DAYS: u32 = 7;
|
||||
pub const TICKETBOOK_VALIDITY_DAYS: u64 = 7;
|
||||
|
||||
/// Specifies the number of tickets in each issued ticketbook.
|
||||
pub const TICKETBOOK_SIZE: u64 = 50;
|
||||
|
||||
/// This type is defined mostly for the purposes of having constants (like sizes) associated with given variants
|
||||
/// It's not meant to be serialised or have any fancy traits defined on it (in this crate)
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum TicketTypeRepr {
|
||||
pub enum TicketbookType {
|
||||
#[default]
|
||||
V1MixnetEntry = 0,
|
||||
V1MixnetExit = 1,
|
||||
V1WireguardEntry = 2,
|
||||
V1WireguardExit = 3,
|
||||
MixnetEntry = 0,
|
||||
MixnetExit = 1,
|
||||
WireguardEntry = 2,
|
||||
WireguardExit = 3,
|
||||
}
|
||||
|
||||
impl TicketTypeRepr {
|
||||
impl TicketbookType {
|
||||
pub const WIREGUARD_ENTRY_TICKET_SIZE: u64 = 500 * 1024 * 1024; // 500 MB
|
||||
|
||||
// TBD:
|
||||
@@ -30,10 +28,10 @@ impl TicketTypeRepr {
|
||||
/// How much bandwidth (in bytes) one ticket can grant
|
||||
pub const fn bandwidth_value(&self) -> u64 {
|
||||
match self {
|
||||
TicketTypeRepr::V1MixnetEntry => Self::MIXNET_ENTRY_TICKET_SIZE,
|
||||
TicketTypeRepr::V1MixnetExit => Self::MIXNET_EXIT_TICKET_SIZE,
|
||||
TicketTypeRepr::V1WireguardEntry => Self::WIREGUARD_ENTRY_TICKET_SIZE,
|
||||
TicketTypeRepr::V1WireguardExit => Self::WIREGUARD_EXIT_TICKET_SIZE,
|
||||
TicketbookType::MixnetEntry => Self::MIXNET_ENTRY_TICKET_SIZE,
|
||||
TicketbookType::MixnetExit => Self::MIXNET_EXIT_TICKET_SIZE,
|
||||
TicketbookType::WireguardEntry => Self::WIREGUARD_ENTRY_TICKET_SIZE,
|
||||
TicketbookType::WireguardExit => Self::WIREGUARD_EXIT_TICKET_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
pub mod constants;
|
||||
pub mod ecash;
|
||||
|
||||
// if you haven't read the Cargo.toml file, the reason for all the feature-locking is that
|
||||
// this crate is imported into the ecash contract
|
||||
//
|
||||
// so if you're thinking of adding a new thing, consider feature-locking it and then just adding it to default feature
|
||||
|
||||
#[cfg(all(feature = "env", feature = "network"))]
|
||||
pub mod env_setup;
|
||||
pub mod mainnet;
|
||||
|
||||
@@ -32,7 +32,6 @@ pub const NYXD_URL: &str = "https://rpc.nymtech.net";
|
||||
pub const NYM_API: &str = "https://validator.nymtech.net/api/";
|
||||
pub const NYXD_WS: &str = "wss://rpc.nymtech.net/websocket";
|
||||
pub const EXPLORER_API: &str = "https://explorer.nymtech.net/api/";
|
||||
pub const NYM_VPN_API: &str = "https://nymvpn.net/api/";
|
||||
|
||||
// I'm making clippy mad on purpose, because that url HAS TO be updated and deployed before merging
|
||||
pub const EXIT_POLICY_URL: &str =
|
||||
@@ -125,7 +124,6 @@ pub fn export_to_env() {
|
||||
set_var_to_default(var_names::NYXD_WEBSOCKET, NYXD_WS);
|
||||
set_var_to_default(var_names::EXPLORER_API, EXPLORER_API);
|
||||
set_var_to_default(var_names::EXIT_POLICY_URL, EXIT_POLICY_URL);
|
||||
set_var_to_default(var_names::NYM_VPN_API, NYM_VPN_API);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "env", feature = "network"))]
|
||||
|
||||
@@ -33,7 +33,6 @@ pub struct NymNetworkDetails {
|
||||
pub endpoints: Vec<ValidatorDetails>,
|
||||
pub contracts: NymContracts,
|
||||
pub explorer_api: Option<String>,
|
||||
pub nym_vpn_api_url: Option<String>,
|
||||
}
|
||||
|
||||
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
|
||||
@@ -63,7 +62,6 @@ impl NymNetworkDetails {
|
||||
endpoints: Default::default(),
|
||||
contracts: Default::default(),
|
||||
explorer_api: Default::default(),
|
||||
nym_vpn_api_url: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +120,6 @@ impl NymNetworkDetails {
|
||||
.with_multisig_contract(get_optional_env(var_names::MULTISIG_CONTRACT_ADDRESS))
|
||||
.with_coconut_dkg_contract(get_optional_env(var_names::COCONUT_DKG_CONTRACT_ADDRESS))
|
||||
.with_explorer_api(get_optional_env(var_names::EXPLORER_API))
|
||||
.with_nym_vpn_api_url(get_optional_env(var_names::NYM_VPN_API))
|
||||
}
|
||||
|
||||
pub fn new_mainnet() -> Self {
|
||||
@@ -150,7 +147,6 @@ impl NymNetworkDetails {
|
||||
),
|
||||
},
|
||||
explorer_api: parse_optional_str(mainnet::EXPLORER_API),
|
||||
nym_vpn_api_url: parse_optional_str(mainnet::NYM_VPN_API),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,19 +255,6 @@ impl NymNetworkDetails {
|
||||
self.explorer_api = endpoint.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_nym_vpn_api_url<S: Into<String>>(mut self, endpoint: Option<S>) -> Self {
|
||||
self.nym_vpn_api_url = endpoint.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn nym_vpn_api_url(&self) -> Option<Url> {
|
||||
self.nym_vpn_api_url.as_ref().map(|url| {
|
||||
url.parse()
|
||||
.expect("the provided nym-vpn api url is invalid!")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
|
||||
@@ -24,7 +24,6 @@ pub const NYM_API: &str = "NYM_API";
|
||||
pub const NYXD_WEBSOCKET: &str = "NYXD_WS";
|
||||
pub const EXPLORER_API: &str = "EXPLORER_API";
|
||||
pub const EXIT_POLICY_URL: &str = "EXIT_POLICY";
|
||||
pub const NYM_VPN_API: &str = "NYM_VPN_API";
|
||||
|
||||
pub const DKG_TIME_CONFIGURATION: &str = "DKG_TIME_CONFIGURATION";
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ fn bench_coin_signing(c: &mut Criterion) {
|
||||
|
||||
// ISSUING AUTHORITY BENCHMARK: issue a set of (partial) signatures for coin indices
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[IssuingAuthority] sign_coin_indices_L_{}",
|
||||
params.get_total_coins()
|
||||
),
|
||||
@@ -47,7 +47,7 @@ fn bench_coin_signing(c: &mut Criterion) {
|
||||
verify_coin_indices_signatures(&verification_key, &vk_i_auth, &partial_signatures).is_ok()
|
||||
);
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] verify_coin_indices_signatures_L_{}",
|
||||
params.get_total_coins()
|
||||
),
|
||||
@@ -99,7 +99,7 @@ fn bench_aggregate_coin_indices_signatures(c: &mut Criterion) {
|
||||
|
||||
// CLIENT: verify all the partial signature vectors and aggregate into a single vector of signed coin indices
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] aggregate_coin_indices_signatures_from_{}_issuing_authorities_L_{}",
|
||||
authorities_keypairs.len(),
|
||||
params.get_total_coins(),
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use itertools::izip;
|
||||
use nym_compact_ecash::identify::{identify, IdentifyResult};
|
||||
use nym_compact_ecash::scheme::expiration_date_signatures::date_scalar;
|
||||
use nym_compact_ecash::scheme::keygen::SecretKeyAuth;
|
||||
use nym_compact_ecash::setup::Parameters;
|
||||
use nym_compact_ecash::tests::helpers::{
|
||||
@@ -14,7 +15,6 @@ use nym_compact_ecash::{
|
||||
ttp_keygen, withdrawal_request, PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser,
|
||||
VerificationKeyAuth,
|
||||
};
|
||||
use nym_network_defaults::TicketTypeRepr;
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
struct BenchCase {
|
||||
@@ -30,14 +30,13 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
// group.sample_size(300);
|
||||
// group.measurement_time(Duration::from_secs(1500));
|
||||
|
||||
let spend_date = 1701907200; // Dec 07 2023 00:00:00
|
||||
let expiration_date = 1702166400; // Dec 10 2023 00:00:00
|
||||
let encoded_ticket_type = TicketTypeRepr::default() as u8;
|
||||
let expiration_date = 1703721600; // Dec 28 2023
|
||||
let spend_date = 1701907200; // Dec 07 2023
|
||||
|
||||
let case = BenchCase {
|
||||
num_authorities: 100,
|
||||
threshold_p: 0.7,
|
||||
ll: 50,
|
||||
ll: 1000,
|
||||
spend_vv: 1,
|
||||
case_nr_pub_keys: 99,
|
||||
};
|
||||
@@ -84,29 +83,15 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
.unwrap();
|
||||
|
||||
// ISSUANCE PHASE
|
||||
let (req, req_info) = withdrawal_request(
|
||||
user_keypair.secret_key(),
|
||||
expiration_date,
|
||||
encoded_ticket_type,
|
||||
)
|
||||
.unwrap();
|
||||
let (req, req_info) = withdrawal_request(user_keypair.secret_key(), expiration_date).unwrap();
|
||||
|
||||
// CLIENT BENCHMARK: prepare a single withdrawal request
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] withdrawal_request_{}_authorities_{}_L_{}_threshold",
|
||||
case.num_authorities, case.ll, case.threshold_p,
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
withdrawal_request(
|
||||
user_keypair.secret_key(),
|
||||
expiration_date,
|
||||
encoded_ticket_type,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
|b| b.iter(|| withdrawal_request(user_keypair.secret_key(), expiration_date).unwrap()),
|
||||
);
|
||||
|
||||
// ISSUING AUTHRORITY BENCHMARK: Benchmark the issue function
|
||||
@@ -114,7 +99,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
let mut rng = rand::thread_rng();
|
||||
let keypair = authorities_keypairs.choose(&mut rng).unwrap();
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Issuing Authority] issue_partial_wallet_with_L_{}",
|
||||
case.ll,
|
||||
),
|
||||
@@ -125,7 +110,6 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
user_keypair.public_key(),
|
||||
&req,
|
||||
expiration_date,
|
||||
encoded_ticket_type,
|
||||
)
|
||||
})
|
||||
},
|
||||
@@ -138,7 +122,6 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
user_keypair.public_key(),
|
||||
&req,
|
||||
expiration_date,
|
||||
encoded_ticket_type,
|
||||
);
|
||||
wallet_blinded_signatures.push(blind_signature.unwrap());
|
||||
}
|
||||
@@ -147,7 +130,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
let w = wallet_blinded_signatures.first().unwrap();
|
||||
let vk = verification_keys_auth.first().unwrap();
|
||||
group.bench_function(
|
||||
format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.ll,),
|
||||
&format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.ll,),
|
||||
|b| b.iter(|| issue_verify(vk, user_keypair.secret_key(), w, &req_info, 1).unwrap()),
|
||||
);
|
||||
|
||||
@@ -163,7 +146,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
|
||||
// CLIENT BENCHMARK: aggregating all partial wallets
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] aggregate_wallets_with_L_{}_threshold_{}",
|
||||
case.ll, case.threshold_p,
|
||||
),
|
||||
@@ -196,7 +179,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
};
|
||||
// CLIENT BENCHMARK: spend a single coin from the wallet
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] spend_a_single_coin_L_{}_threshold_{}",
|
||||
case.ll, case.threshold_p,
|
||||
),
|
||||
@@ -233,14 +216,14 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
|
||||
// MERCHANT BENCHMARK: verify whether the submitted payment is legit
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Merchant] spend_verify_of_a_single_payment_L_{}_threshold_{}",
|
||||
case.ll, case.threshold_p,
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
payment
|
||||
.spend_verify(&verification_key, &pay_info, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info, date_scalar(spend_date))
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
@@ -280,7 +263,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
|
||||
// MERCHANT BENCHMARK: identify double spending
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Merchant] identify_L_{}_threshold_{}_spend_vv_{}_pks_{}",
|
||||
case.ll,
|
||||
case.threshold_p,
|
||||
|
||||
@@ -21,7 +21,7 @@ fn bench_partial_sign_expiration_date(c: &mut Criterion) {
|
||||
|
||||
// ISSUING AUTHORITY BENCHMARK: issue a set of (partial) signatures for a given expiration date
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[IssuingAuthority] sign_expiration_date_{}_validity_period",
|
||||
constants::CRED_VALIDITY_PERIOD_DAYS,
|
||||
),
|
||||
@@ -31,7 +31,7 @@ fn bench_partial_sign_expiration_date(c: &mut Criterion) {
|
||||
// CLIENT: verify the correctness of the set of (partial) signatures for a given expiration date
|
||||
assert!(verify_valid_dates_signatures(&vk_i_auth, &partial_exp_sig, expiration_date).is_ok());
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] verify_valid_dates_signatures_{}_validity_period",
|
||||
constants::CRED_VALIDITY_PERIOD_DAYS,
|
||||
),
|
||||
@@ -78,7 +78,7 @@ fn bench_aggregate_expiration_date_signatures(c: &mut Criterion) {
|
||||
|
||||
// CLIENT: verify all the partial signature vectors and aggregate into a single vector of signed valid dates
|
||||
group.bench_function(
|
||||
format!(
|
||||
&format!(
|
||||
"[Client] aggregate_expiration_signatures_from_{}_issuing_authorities_{}_validity_period",
|
||||
constants::CRED_VALIDITY_PERIOD_DAYS, authorities_keypairs.len(),
|
||||
),
|
||||
|
||||
@@ -9,9 +9,9 @@ pub const PUBLIC_ATTRIBUTES_LEN: usize = 2; //expiration date and ticket type
|
||||
pub const PRIVATE_ATTRIBUTES_LEN: usize = 2; //user and wallet secret
|
||||
pub const ATTRIBUTES_LEN: usize = PUBLIC_ATTRIBUTES_LEN + PRIVATE_ATTRIBUTES_LEN; // number of attributes encoded in a single zk-nym credential
|
||||
|
||||
pub const CRED_VALIDITY_PERIOD_DAYS: u32 = TICKETBOOK_VALIDITY_DAYS;
|
||||
pub const CRED_VALIDITY_PERIOD_DAYS: u64 = TICKETBOOK_VALIDITY_DAYS;
|
||||
|
||||
pub(crate) const SECONDS_PER_DAY: u32 = 86400;
|
||||
pub(crate) const SECONDS_PER_DAY: u64 = 86400;
|
||||
|
||||
/// Total number of tickets in each issued ticket book.
|
||||
pub const NB_TICKETS: u64 = TICKETBOOK_SIZE;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::utils::try_deserialize_g1_projective;
|
||||
use crate::{CompactEcashError, EncodedDate, EncodedTicketType};
|
||||
use bls12_381::{G1Projective, Scalar};
|
||||
use crate::CompactEcashError;
|
||||
use bls12_381::G1Projective;
|
||||
use group::Curve;
|
||||
use std::any::{type_name, Any};
|
||||
|
||||
@@ -35,27 +35,3 @@ pub(crate) fn recover_g1_tuple<T: Any>(
|
||||
|
||||
Ok((first, second))
|
||||
}
|
||||
|
||||
pub fn date_scalar(date: EncodedDate) -> Scalar {
|
||||
Scalar::from(date as u64)
|
||||
}
|
||||
|
||||
// TODO: this will not work for **all** scalars,
|
||||
// but timestamps have extremely (relatively speaking) limited range,
|
||||
// so this should be fine
|
||||
pub(crate) fn scalar_date(scalar: &Scalar) -> EncodedDate {
|
||||
let b = scalar.to_bytes();
|
||||
u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as EncodedDate
|
||||
}
|
||||
|
||||
pub fn type_scalar(t_type: EncodedTicketType) -> Scalar {
|
||||
Scalar::from(t_type as u64)
|
||||
}
|
||||
|
||||
// TODO: this will not work for **all** scalars,
|
||||
// but ticket types have extremely (relatively speaking) limited range,
|
||||
// so this should be fine
|
||||
pub(crate) fn scalar_type(scalar: &Scalar) -> EncodedTicketType {
|
||||
let b = scalar.to_bytes();
|
||||
u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as EncodedTicketType
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ pub use crate::error::CompactEcashError;
|
||||
pub use crate::traits::Bytable;
|
||||
pub use bls12_381::G1Projective;
|
||||
pub use common_types::{BlindedSignature, Signature};
|
||||
pub use helpers::{date_scalar, type_scalar};
|
||||
pub use scheme::aggregation::aggregate_verification_keys;
|
||||
pub use scheme::aggregation::aggregate_wallets;
|
||||
pub use scheme::identify;
|
||||
@@ -43,8 +42,6 @@ mod traits;
|
||||
pub mod utils;
|
||||
|
||||
pub type Attribute = Scalar;
|
||||
pub type EncodedTicketType = u8;
|
||||
pub type EncodedDate = u32;
|
||||
|
||||
pub fn ecash_parameters() -> &'static setup::Parameters {
|
||||
static ECASH_PARAMS: OnceLock<setup::Parameters> = OnceLock::new();
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use core::iter::Sum;
|
||||
use core::ops::Mul;
|
||||
|
||||
use bls12_381::{G2Prepared, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::common_types::{PartialSignature, Signature, SignatureShare, SignerIndex};
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::helpers::{scalar_date, scalar_type};
|
||||
use crate::scheme::expiration_date_signatures::scalar_date;
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::withdrawal::RequestInfo;
|
||||
use crate::scheme::{PartialWallet, Wallet, WalletSignatures};
|
||||
use crate::utils::{check_bilinear_pairing, perform_lagrangian_interpolation_at_origin};
|
||||
use crate::utils::{
|
||||
check_bilinear_pairing, perform_lagrangian_interpolation_at_origin, scalar_type,
|
||||
};
|
||||
use crate::{ecash_group_parameters, Attribute};
|
||||
use bls12_381::{G2Prepared, G2Projective, Scalar};
|
||||
use core::iter::Sum;
|
||||
use core::ops::Mul;
|
||||
use group::Curve;
|
||||
use itertools::Itertools;
|
||||
|
||||
pub(crate) trait Aggregatable: Sized {
|
||||
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::common_types::{Signature, SignerIndex};
|
||||
use crate::constants;
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::helpers::date_scalar;
|
||||
use crate::scheme::keygen::{SecretKeyAuth, VerificationKeyAuth};
|
||||
use crate::utils::generate_lagrangian_coefficients_at_origin;
|
||||
use crate::utils::{batch_verify_signatures, hash_g1};
|
||||
use crate::{constants, EncodedDate};
|
||||
use bls12_381::{G1Projective, Scalar};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -20,8 +19,8 @@ pub type PartialExpirationDateSignature = ExpirationDateSignature;
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AnnotatedExpirationDateSignature {
|
||||
pub signature: ExpirationDateSignature,
|
||||
pub expiration_timestamp: EncodedDate,
|
||||
pub spending_timestamp: EncodedDate,
|
||||
pub expiration_timestamp: u64,
|
||||
pub spending_timestamp: u64,
|
||||
}
|
||||
|
||||
impl Borrow<ExpirationDateSignature> for AnnotatedExpirationDateSignature {
|
||||
@@ -67,17 +66,17 @@ where
|
||||
/// The validity period is determined by the constant `CRED_VALIDITY_PERIOD` in the `constants` module.
|
||||
pub fn sign_expiration_date(
|
||||
sk_auth: &SecretKeyAuth,
|
||||
expiration_unix_timestamp: EncodedDate,
|
||||
expiration_unix_timestamp: u64,
|
||||
) -> Result<Vec<AnnotatedExpirationDateSignature>> {
|
||||
if sk_auth.ys.len() < 3 {
|
||||
return Err(CompactEcashError::KeyTooShort);
|
||||
}
|
||||
let m0: Scalar = date_scalar(expiration_unix_timestamp);
|
||||
let m0: Scalar = Scalar::from(expiration_unix_timestamp);
|
||||
let m2: Scalar = constants::TYPE_EXP;
|
||||
|
||||
let partial_s_exponent = sk_auth.x + sk_auth.ys[0] * m0 + sk_auth.ys[2] * m2;
|
||||
|
||||
let sign_expiration = |offset: u32| {
|
||||
let sign_expiration = |offset: u64| {
|
||||
// we produce tuples of (assuming CRED_VALIDITY_PERIOD_DAYS = 30):
|
||||
// (expiration, expiration - 29)
|
||||
// (expiration, expiration - 28)
|
||||
@@ -85,7 +84,7 @@ pub fn sign_expiration_date(
|
||||
// (expiration, expiration)
|
||||
let spending_unix_timestamp = expiration_unix_timestamp
|
||||
- ((constants::CRED_VALIDITY_PERIOD_DAYS - offset - 1) * constants::SECONDS_PER_DAY);
|
||||
let m1: Scalar = date_scalar(spending_unix_timestamp);
|
||||
let m1: Scalar = Scalar::from(spending_unix_timestamp);
|
||||
// Compute the hash
|
||||
let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat());
|
||||
// Sign the attributes by performing scalar-point multiplications and accumulating the result
|
||||
@@ -137,22 +136,22 @@ pub fn sign_expiration_date(
|
||||
pub fn verify_valid_dates_signatures<B>(
|
||||
vk: &VerificationKeyAuth,
|
||||
signatures: &[B],
|
||||
expiration_date: EncodedDate,
|
||||
expiration_date: u64,
|
||||
) -> Result<()>
|
||||
where
|
||||
B: Borrow<ExpirationDateSignature>,
|
||||
{
|
||||
let m0: Scalar = date_scalar(expiration_date);
|
||||
let m0: Scalar = Scalar::from(expiration_date);
|
||||
let m2: Scalar = constants::TYPE_EXP;
|
||||
|
||||
let partially_signed = vk.alpha + vk.beta_g2[0] * m0 + vk.beta_g2[2] * m2;
|
||||
let mut pairing_terms = Vec::with_capacity(signatures.len());
|
||||
|
||||
for (i, sig) in signatures.iter().enumerate() {
|
||||
let l = i as u32;
|
||||
let l = i as u64;
|
||||
let valid_date = expiration_date
|
||||
- ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY);
|
||||
let m1: Scalar = date_scalar(valid_date);
|
||||
let m1: Scalar = Scalar::from(valid_date);
|
||||
|
||||
// Compute the hash
|
||||
let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat());
|
||||
@@ -200,7 +199,7 @@ where
|
||||
///
|
||||
fn _aggregate_expiration_signatures<B>(
|
||||
vk: &VerificationKeyAuth,
|
||||
expiration_date: EncodedDate,
|
||||
expiration_date: u64,
|
||||
signatures_shares: &[ExpirationDateSignatureShare<B>],
|
||||
validate_shares: bool,
|
||||
) -> Result<Vec<ExpirationDateSignature>>
|
||||
@@ -245,12 +244,12 @@ where
|
||||
let mut aggregated_date_signatures: Vec<ExpirationDateSignature> =
|
||||
Vec::with_capacity(constants::CRED_VALIDITY_PERIOD_DAYS as usize);
|
||||
|
||||
let m0: Scalar = date_scalar(expiration_date);
|
||||
let m0: Scalar = Scalar::from(expiration_date);
|
||||
|
||||
for l in 0..constants::CRED_VALIDITY_PERIOD_DAYS {
|
||||
let valid_date = expiration_date
|
||||
- ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY);
|
||||
let m1: Scalar = date_scalar(valid_date);
|
||||
let m1: Scalar = Scalar::from(valid_date);
|
||||
// Compute the hash
|
||||
let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat());
|
||||
|
||||
@@ -300,7 +299,7 @@ where
|
||||
///
|
||||
pub fn aggregate_expiration_signatures<B>(
|
||||
vk: &VerificationKeyAuth,
|
||||
expiration_date: EncodedDate,
|
||||
expiration_date: u64,
|
||||
signatures_shares: &[ExpirationDateSignatureShare<B>],
|
||||
) -> Result<Vec<ExpirationDateSignature>>
|
||||
where
|
||||
@@ -315,7 +314,7 @@ where
|
||||
/// It further annotates the result with timestamp information
|
||||
pub fn aggregate_annotated_expiration_signatures(
|
||||
vk: &VerificationKeyAuth,
|
||||
expiration_date: EncodedDate,
|
||||
expiration_date: u64,
|
||||
signatures_shares: &[ExpirationDateSignatureShare<AnnotatedExpirationDateSignature>],
|
||||
) -> Result<Vec<AnnotatedExpirationDateSignature>> {
|
||||
// it's sufficient to just verify the first share as if the rest of them don't match,
|
||||
@@ -333,7 +332,7 @@ pub fn aggregate_annotated_expiration_signatures(
|
||||
return Err(CompactEcashError::ExpirationDateSignatureVerification);
|
||||
}
|
||||
|
||||
let l = i as u32;
|
||||
let l = i as u64;
|
||||
let expected_spending = sig.expiration_timestamp
|
||||
- ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY);
|
||||
|
||||
@@ -362,7 +361,7 @@ pub fn aggregate_annotated_expiration_signatures(
|
||||
/// It is expected the caller has already pre-validated them via manual calls to `verify_valid_dates_signatures`
|
||||
pub fn unchecked_aggregate_expiration_signatures(
|
||||
vk: &VerificationKeyAuth,
|
||||
expiration_date: EncodedDate,
|
||||
expiration_date: u64,
|
||||
signatures_shares: &[ExpirationDateSignatureShare],
|
||||
) -> Result<Vec<ExpirationDateSignature>> {
|
||||
_aggregate_expiration_signatures(vk, expiration_date, signatures_shares, false)
|
||||
@@ -384,13 +383,13 @@ pub fn unchecked_aggregate_expiration_signatures(
|
||||
/// If a valid index is found, returns `Ok(index)`. If no valid index is found
|
||||
/// (i.e., `spend_date` is earlier than `expiration_date - 30`), returns `Err(InvalidDateError)`.
|
||||
///
|
||||
pub fn find_index(spend_date: EncodedDate, expiration_date: EncodedDate) -> Result<usize> {
|
||||
pub fn find_index(spend_date: u64, expiration_date: u64) -> Result<usize> {
|
||||
let start_date =
|
||||
expiration_date - ((constants::CRED_VALIDITY_PERIOD_DAYS - 1) * constants::SECONDS_PER_DAY);
|
||||
|
||||
if spend_date >= start_date {
|
||||
let index_a = ((spend_date - start_date) / constants::SECONDS_PER_DAY) as usize;
|
||||
if index_a as u32 >= constants::CRED_VALIDITY_PERIOD_DAYS {
|
||||
if index_a as u64 >= constants::CRED_VALIDITY_PERIOD_DAYS {
|
||||
Err(CompactEcashError::SpendDateTooLate)
|
||||
} else {
|
||||
Ok(index_a)
|
||||
@@ -400,6 +399,18 @@ pub fn find_index(spend_date: EncodedDate, expiration_date: EncodedDate) -> Resu
|
||||
}
|
||||
}
|
||||
|
||||
pub fn date_scalar(date: u64) -> Scalar {
|
||||
Scalar::from(date)
|
||||
}
|
||||
|
||||
// TODO: this will not work for **all** scalars,
|
||||
// but timestamps have extremely (relatively speaking) limited range,
|
||||
// so this should be fine
|
||||
pub fn scalar_date(scalar: &Scalar) -> u64 {
|
||||
let b = scalar.to_bytes();
|
||||
u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -54,6 +54,7 @@ pub fn identify(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::scheme::expiration_date_signatures::date_scalar;
|
||||
use crate::scheme::identify::{identify, IdentifyResult};
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser};
|
||||
use crate::setup::Parameters;
|
||||
@@ -164,12 +165,12 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(payment1
|
||||
.spend_verify(&verification_key, &pay_info1, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
let payment2 = payment1.clone();
|
||||
assert!(payment2
|
||||
.spend_verify(&verification_key, &pay_info1, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
let identify_result = identify(&payment1, &payment2, pay_info1, pay_info1);
|
||||
@@ -274,7 +275,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(payment1
|
||||
.spend_verify(&verification_key, &pay_info1, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
let pay_info2 = PayInfo {
|
||||
@@ -294,7 +295,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(payment2
|
||||
.spend_verify(&verification_key, &pay_info2, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info2, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
let identify_result = identify(&payment1, &payment2, pay_info1, pay_info2);
|
||||
@@ -410,7 +411,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(payment1
|
||||
.spend_verify(&verification_key, &pay_info1, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
// let's reverse the spending counter in the wallet to create a double spending payment
|
||||
@@ -434,7 +435,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(payment2
|
||||
.spend_verify(&verification_key, &pay_info2, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info2, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
let identify_result = identify(&payment1, &payment2, pay_info1, pay_info2);
|
||||
@@ -554,7 +555,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(payment1
|
||||
.spend_verify(&verification_key, &pay_info1, spend_date)
|
||||
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
|
||||
.is_ok());
|
||||
|
||||
// let's reverse the spending counter in the wallet to create a double spending payment
|
||||
|
||||
@@ -97,6 +97,10 @@ impl SecretKeyAuth {
|
||||
self.ys.len()
|
||||
}
|
||||
|
||||
pub(crate) fn get_y_by_idx(&self, i: usize) -> Option<&Scalar> {
|
||||
self.ys.get(i)
|
||||
}
|
||||
|
||||
pub fn verification_key(&self) -> VerificationKeyAuth {
|
||||
let params = ecash_group_parameters();
|
||||
let g1 = params.gen1();
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
|
||||
use crate::common_types::{Signature, SignerIndex};
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::helpers::{date_scalar, type_scalar};
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::coin_indices_signatures::CoinIndexSignature;
|
||||
use crate::scheme::expiration_date_signatures::{find_index, ExpirationDateSignature};
|
||||
use crate::scheme::expiration_date_signatures::{date_scalar, find_index, ExpirationDateSignature};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::traits::Bytable;
|
||||
use crate::utils::{
|
||||
batch_verify_signatures, check_bilinear_pairing, hash_to_scalar, try_deserialize_scalar,
|
||||
};
|
||||
use crate::Base58;
|
||||
use crate::{constants, ecash_group_parameters};
|
||||
use crate::{Base58, EncodedDate, EncodedTicketType};
|
||||
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
@@ -229,7 +228,7 @@ impl Wallet {
|
||||
spend_value: u64,
|
||||
valid_dates_signatures: &[ExpirationDateSignature],
|
||||
coin_indices_signatures: &[CoinIndexSignature],
|
||||
spend_date_timestamp: EncodedDate,
|
||||
spend_date_timestamp: u64,
|
||||
) -> Result<Payment> {
|
||||
self.check_remaining_allowance(params, spend_value)?;
|
||||
|
||||
@@ -270,8 +269,8 @@ pub struct WalletSignatures {
|
||||
#[zeroize(skip)]
|
||||
sig: Signature,
|
||||
v: Scalar,
|
||||
expiration_date_timestamp: EncodedDate,
|
||||
t_type: EncodedTicketType,
|
||||
expiration_date_timestamp: u64,
|
||||
t_type: u64,
|
||||
}
|
||||
|
||||
impl WalletSignatures {
|
||||
@@ -315,8 +314,8 @@ pub fn compute_pay_info_hash(pay_info: &PayInfo, k: u64) -> Scalar {
|
||||
}
|
||||
|
||||
impl WalletSignatures {
|
||||
// signature size (96) + secret size (32) + expiration size (4) + t_type (1)
|
||||
pub const SERIALISED_SIZE: usize = 133;
|
||||
// signature size (96) + secret size (32) + expiration size (8) + t_type (8)
|
||||
pub const SERIALISED_SIZE: usize = 144;
|
||||
|
||||
pub fn signature(&self) -> &Signature {
|
||||
&self.sig
|
||||
@@ -336,8 +335,8 @@ impl WalletSignatures {
|
||||
let mut bytes = [0u8; Self::SERIALISED_SIZE];
|
||||
bytes[0..96].copy_from_slice(&self.sig.to_bytes());
|
||||
bytes[96..128].copy_from_slice(&self.v.to_bytes());
|
||||
bytes[128..132].copy_from_slice(&self.expiration_date_timestamp.to_be_bytes());
|
||||
bytes[132] = self.t_type;
|
||||
bytes[128..136].copy_from_slice(&self.expiration_date_timestamp.to_be_bytes());
|
||||
bytes[136..144].copy_from_slice(&self.t_type.to_be_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
@@ -357,12 +356,15 @@ impl WalletSignatures {
|
||||
let v_bytes: &[u8; 32] = &bytes[96..128].try_into().unwrap();
|
||||
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let expiration_date_bytes = bytes[128..132].try_into().unwrap();
|
||||
let expiration_date_bytes = bytes[128..136].try_into().unwrap();
|
||||
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let t_type_bytes = bytes[136..].try_into().unwrap();
|
||||
|
||||
let sig = Signature::try_from(sig_bytes.as_slice())?;
|
||||
let v = Scalar::from_bytes(v_bytes).unwrap();
|
||||
let expiration_date_timestamp = EncodedDate::from_be_bytes(expiration_date_bytes);
|
||||
let t_type = bytes[132];
|
||||
let expiration_date_timestamp = u64::from_be_bytes(expiration_date_bytes);
|
||||
let t_type = u64::from_be_bytes(t_type_bytes);
|
||||
|
||||
Ok(WalletSignatures {
|
||||
sig,
|
||||
@@ -399,7 +401,7 @@ impl WalletSignatures {
|
||||
spend_value: u64,
|
||||
valid_dates_signatures: &[BE],
|
||||
coin_indices_signatures: &[BI],
|
||||
spend_date_timestamp: EncodedDate,
|
||||
spend_date_timestamp: u64,
|
||||
) -> Result<Payment>
|
||||
where
|
||||
BI: Borrow<CoinIndexSignature>,
|
||||
@@ -594,7 +596,7 @@ fn pseudorandom_f_g_v(params: &GroupParameters, v: &Scalar, l: u64) -> Result<G1
|
||||
/// * `params` - A reference to the group parameters required for the computation.
|
||||
/// * `verification_key` - The global verification key of the signing authorities.
|
||||
/// * `attributes` - A slice of private attributes associated with the wallet.
|
||||
/// * `blinding_factor` - The blinding factor used to randomise the wallet's signature.
|
||||
/// * `blinding_factor` - The blinding factor used used to randomise the wallet's signature.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
@@ -687,7 +689,7 @@ pub struct Payment {
|
||||
pub aa: Vec<G1Projective>,
|
||||
pub spend_value: u64,
|
||||
pub cc: G1Projective,
|
||||
pub t_type: EncodedTicketType,
|
||||
pub t_type: u64,
|
||||
pub zk_proof: SpendProof,
|
||||
}
|
||||
|
||||
@@ -718,7 +720,7 @@ impl Payment {
|
||||
return Err(CompactEcashError::SpendSignaturesValidity);
|
||||
}
|
||||
|
||||
let kappa_type = self.kappa + verification_key.beta_g2[3] * type_scalar(self.t_type);
|
||||
let kappa_type = self.kappa + verification_key.beta_g2[3] * Scalar::from(self.t_type);
|
||||
if !check_bilinear_pairing(
|
||||
&self.sig.h.to_affine(),
|
||||
&G2Prepared::from(kappa_type.to_affine()),
|
||||
@@ -948,7 +950,7 @@ impl Payment {
|
||||
&self,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
pay_info: &PayInfo,
|
||||
spend_date: EncodedDate,
|
||||
spend_date: Scalar,
|
||||
) -> Result<()> {
|
||||
// check if all serial numbers are different
|
||||
self.no_duplicate_serial_numbers()?;
|
||||
@@ -957,7 +959,7 @@ impl Payment {
|
||||
// Verify whether the payment signature and kappa are correct
|
||||
self.check_signature_validity(verification_key)?;
|
||||
// Verify whether the expiration date signature and kappa_e are correct
|
||||
self.check_exp_signature_validity(verification_key, date_scalar(spend_date))?;
|
||||
self.check_exp_signature_validity(verification_key, spend_date)?;
|
||||
// Verify whether the coin indices signatures and kappa_k are correct
|
||||
self.batch_check_coin_index_signatures(verification_key)?;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user