From e6c5eddbe58a473da4bf118344ef4174266dad58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 16 Aug 2024 11:56:48 +0100 Subject: [PATCH 01/41] bugfix: make sure DKG parse data out of events if logs are empty this will be the case on post 0.50 chains --- .../src/nyxd/cosmwasm_client/helpers.rs | 2 +- .../src/nyxd/cosmwasm_client/logs.rs | 4 ++- .../validator-client/src/nyxd/helpers.rs | 34 ++++++++++++++++++- nym-api/src/ecash/dkg/client.rs | 21 ++++++------ nym-api/src/ecash/dkg/key_derivation.rs | 29 ++++++++-------- 5 files changed, 63 insertions(+), 27 deletions(-) diff --git a/common/client-libs/validator-client/src/nyxd/cosmwasm_client/helpers.rs b/common/client-libs/validator-client/src/nyxd/cosmwasm_client/helpers.rs index c437125b16..2212aa4cff 100644 --- a/common/client-libs/validator-client/src/nyxd/cosmwasm_client/helpers.rs +++ b/common/client-libs/validator-client/src/nyxd/cosmwasm_client/helpers.rs @@ -1,6 +1,7 @@ // Copyright 2021 - Nym Technologies SA // 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; @@ -9,7 +10,6 @@ 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 { diff --git a/common/client-libs/validator-client/src/nyxd/cosmwasm_client/logs.rs b/common/client-libs/validator-client/src/nyxd/cosmwasm_client/logs.rs index 4a31a1fc7e..3d5ecab961 100644 --- a/common/client-libs/validator-client/src/nyxd/cosmwasm_client/logs.rs +++ b/common/client-libs/validator-client/src/nyxd/cosmwasm_client/logs.rs @@ -21,7 +21,8 @@ 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. -pub fn find_attribute<'a>( +#[deprecated] +pub fn find_attribute_in_logs<'a>( logs: &'a [Log], event_type: &str, attribute_key: &str, @@ -35,6 +36,7 @@ pub fn find_attribute<'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 { let maybe_attributes = logs .iter() diff --git a/common/client-libs/validator-client/src/nyxd/helpers.rs b/common/client-libs/validator-client/src/nyxd/helpers.rs index cec865252a..3fbfdaaaf3 100644 --- a/common/client-libs/validator-client/src/nyxd/helpers.rs +++ b/common/client-libs/validator-client/src/nyxd/helpers.rs @@ -1,12 +1,24 @@ // Copyright 2023 - Nym Technologies SA // 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 { - let event = tx.tx_result.events.iter().find(|e| e.kind == event_type)?; + 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 { + let event = 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 @@ -16,3 +28,23 @@ pub fn find_tx_attribute(tx: &TxResponse, event_type: &str, attribute_key: &str) })?; 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 { + // 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) +} diff --git a/nym-api/src/ecash/dkg/client.rs b/nym-api/src/ecash/dkg/client.rs index 1471083060..5c8f993690 100644 --- a/nym-api/src/ecash/dkg/client.rs +++ b/nym-api/src/ecash/dkg/client.rs @@ -16,8 +16,9 @@ use nym_coconut_dkg_common::types::{ use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare}; use nym_contracts_common::IdentityKey; use nym_dkg::Threshold; -use nym_validator_client::nyxd::cosmwasm_client::logs::{find_attribute, NODE_INDEX}; +use nym_validator_client::nyxd::cosmwasm_client::logs::NODE_INDEX; use nym_validator_client::nyxd::cosmwasm_client::types::ExecuteResult; +use nym_validator_client::nyxd::helpers::find_attribute_value_in_logs_or_events; use nym_validator_client::nyxd::AccountId; pub(crate) struct DkgClient { @@ -168,15 +169,15 @@ impl DkgClient { .inner .register_dealer(bte_key, identity_key, announce_address, resharing) .await?; - let node_index = find_attribute(&res.logs, "wasm", NODE_INDEX) - .ok_or(EcashError::NodeIndexRecoveryError { - reason: String::from("node index not found"), - })? - .value - .parse::() - .map_err(|_| EcashError::NodeIndexRecoveryError { - reason: String::from("node index could not be parsed"), - })?; + let node_index = + find_attribute_value_in_logs_or_events(&res.logs, &res.events, "wasm", NODE_INDEX) + .ok_or(EcashError::NodeIndexRecoveryError { + reason: String::from("node index not found"), + })? + .parse::() + .map_err(|_| EcashError::NodeIndexRecoveryError { + reason: String::from("node index could not be parsed"), + })?; Ok(node_index) } diff --git a/nym-api/src/ecash/dkg/key_derivation.rs b/nym-api/src/ecash/dkg/key_derivation.rs index e2ad2a7cb2..23291806b8 100644 --- a/nym-api/src/ecash/dkg/key_derivation.rs +++ b/nym-api/src/ecash/dkg/key_derivation.rs @@ -18,8 +18,9 @@ use nym_dkg::{ bte::{self, decrypt_share}, combine_shares, try_recover_verification_keys, Dealing, }; -use nym_validator_client::nyxd::cosmwasm_client::logs::{find_attribute, Log}; -use nym_validator_client::nyxd::Hash; +use nym_validator_client::nyxd::cosmwasm_client::logs::Log; +use nym_validator_client::nyxd::helpers::find_attribute_value_in_logs_or_events; +use nym_validator_client::nyxd::{Event, Hash}; use rand::{CryptoRng, RngCore}; use std::collections::{BTreeMap, HashMap}; use std::ops::Deref; @@ -453,25 +454,25 @@ impl DkgController { key: &VerificationKeyAuth, resharing: bool, ) -> Result { - fn extract_proposal_id_from_logs( + fn extract_proposal_id( logs: &[Log], + events: &[Event], tx_hash: Hash, ) -> Result { let event_type = "wasm"; let attribute_key = DKG_PROPOSAL_ID; - let proposal_attribute = find_attribute(logs, event_type, attribute_key).ok_or( - KeyDerivationError::MissingProposalIdAttribute { - tx_hash, - event_type: event_type.to_string(), - attribute_key: attribute_key.to_string(), - }, - )?; + let proposal_value = + find_attribute_value_in_logs_or_events(logs, events, event_type, attribute_key) + .ok_or(KeyDerivationError::MissingProposalIdAttribute { + tx_hash, + event_type: event_type.to_string(), + attribute_key: attribute_key.to_string(), + })?; - proposal_attribute - .value + proposal_value .parse() .map_err(|_| KeyDerivationError::UnparsableProposalId { - raw: proposal_attribute.value.clone(), + raw: proposal_value.clone(), }) } @@ -481,7 +482,7 @@ impl DkgController { .submit_verification_key_share(key.to_bs58(), resharing) .await?; let hash = res.transaction_hash; - let proposal_id = extract_proposal_id_from_logs(&res.logs, hash)?; + let proposal_id = extract_proposal_id(&res.logs, &res.events, hash)?; debug!("Submitted own verification key share, proposal id {proposal_id} is attached to it. tx hash: {hash}"); Ok(proposal_id) From c0ea599913872c08dfc153bec9223145939c7717 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Mon, 19 Aug 2024 10:32:21 +0200 Subject: [PATCH 02/41] update changelog and version bump --- CHANGELOG.md | 32 +++++++++++++++++++ Cargo.lock | 16 +++++----- clients/native/Cargo.toml | 2 +- clients/socks5/Cargo.toml | 2 +- explorer-api/Cargo.toml | 2 +- nym-api/Cargo.toml | 2 +- nym-node/Cargo.toml | 2 +- .../network-requester/Cargo.toml | 2 +- tools/nym-cli/Cargo.toml | 2 +- tools/nymvisor/Cargo.toml | 2 +- 10 files changed, 48 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a39429e55..9e685c9e46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,38 @@ 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]) diff --git a/Cargo.lock b/Cargo.lock index 68792a2ad6..0923a3a4f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2240,7 +2240,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "explorer-api" -version = "1.1.38" +version = "1.1.39" dependencies = [ "chrono", "clap 4.5.7", @@ -4204,7 +4204,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "nym-api" -version = "1.1.42" +version = "1.1.43" dependencies = [ "anyhow", "async-trait", @@ -4425,7 +4425,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.40" +version = "1.1.41" dependencies = [ "anyhow", "base64 0.13.1", @@ -4504,7 +4504,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.39" +version = "1.1.40" dependencies = [ "bs58 0.5.1", "clap 4.5.7", @@ -5412,7 +5412,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.40" +version = "1.1.41" dependencies = [ "addr", "anyhow", @@ -5463,7 +5463,7 @@ dependencies = [ [[package]] name = "nym-node" -version = "1.1.6" +version = "1.1.7" dependencies = [ "anyhow", "bip39", @@ -5737,7 +5737,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.39" +version = "1.1.40" dependencies = [ "bs58 0.5.1", "clap 4.5.7", @@ -6259,7 +6259,7 @@ dependencies = [ [[package]] name = "nymvisor" -version = "0.1.5" +version = "0.1.6" dependencies = [ "anyhow", "bytes", diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index f57505eb66..7e253719c2 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-client" -version = "1.1.39" +version = "1.1.40" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] description = "Implementation of the Nym Client" edition = "2021" diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 06754b0b76..ee15f6747c 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-socks5-client" -version = "1.1.39" +version = "1.1.40" authors = ["Dave Hrycyszyn "] description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" edition = "2021" diff --git a/explorer-api/Cargo.toml b/explorer-api/Cargo.toml index 2a33ae5fc8..691c88b67a 100644 --- a/explorer-api/Cargo.toml +++ b/explorer-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "explorer-api" -version = "1.1.38" +version = "1.1.39" edition = "2021" license.workspace = true diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index 551f682c13..800a85bde4 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "nym-api" license = "GPL-3.0" -version = "1.1.42" +version = "1.1.43" authors = [ "Dave Hrycyszyn ", "Jędrzej Stuczyński ", diff --git a/nym-node/Cargo.toml b/nym-node/Cargo.toml index b897f2d008..942de6a37c 100644 --- a/nym-node/Cargo.toml +++ b/nym-node/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-node" -version = "1.1.6" +version = "1.1.7" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 13b710e802..adfdde70c7 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "nym-network-requester" license = "GPL-3.0" -version = "1.1.40" +version = "1.1.41" authors.workspace = true edition.workspace = true rust-version = "1.70" diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index e590e45141..61848f161d 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-cli" -version = "1.1.40" +version = "1.1.41" authors.workspace = true edition = "2021" license.workspace = true diff --git a/tools/nymvisor/Cargo.toml b/tools/nymvisor/Cargo.toml index 8f5658c8d3..6fb6a36e5e 100644 --- a/tools/nymvisor/Cargo.toml +++ b/tools/nymvisor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nymvisor" -version = "0.1.5" +version = "0.1.6" authors.workspace = true repository.workspace = true homepage.workspace = true From 6393d6093fffb6eef2ddd123c85393c97b2df475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 11:31:07 +0100 Subject: [PATCH 03/41] changed parsing of 'credential_data' when importing ticketbooks --- .../commands/src/coconut/import_ticket_book.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/common/commands/src/coconut/import_ticket_book.rs b/common/commands/src/coconut/import_ticket_book.rs index 852f94e34a..2edf281a04 100644 --- a/common/commands/src/coconut/import_ticket_book.rs +++ b/common/commands/src/coconut/import_ticket_book.rs @@ -9,9 +9,17 @@ use nym_credential_storage::initialise_persistent_storage; use nym_id::import_credential; use std::fs; use std::path::PathBuf; +use std::str::FromStr; -fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result> { - bs58::decode(raw).into_vec() +#[derive(Debug, Clone)] +pub struct CredentialDataWrapper(Vec); + +impl FromStr for CredentialDataWrapper { + type Err = bs58::decode::Error; + + fn from_str(s: &str) -> Result { + bs58::decode(s).into_vec().map(CredentialDataWrapper) + } } #[derive(Debug, Parser)] @@ -22,8 +30,8 @@ pub struct Args { pub(crate) client_config: PathBuf, /// Explicitly provide the encoded credential data (as base58) - #[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)] - pub(crate) credential_data: Option>, + #[clap(long, group = "cred_data")] + pub(crate) credential_data: Option, /// Specifies the path to file containing binary credential data #[clap(long, group = "cred_data")] @@ -52,7 +60,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, + Some(data) => data.0, None => { // SAFETY: one of those arguments must have been set fs::read(args.credential_path.unwrap())? From bbf0d06583bfbecda08dda3b61c779ae7479ad73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 12:54:42 +0100 Subject: [PATCH 04/41] updated constants depending on all 30 days expiration --- gateway/src/config/mod.rs | 29 ++++++++++++++++--- .../ecash/credential_sender.rs | 2 +- nym-api/src/ecash/state/helpers.rs | 2 +- nym-node/src/config/entry_gateway.rs | 29 ++++++++++++++++--- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index 0750b3bf0d..5a5c57e3f9 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -10,7 +10,7 @@ use nym_config::{ must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, }; -use nym_network_defaults::{mainnet, DEFAULT_NYM_NODE_HTTP_PORT}; +use nym_network_defaults::{mainnet, DEFAULT_NYM_NODE_HTTP_PORT, TICKETBOOK_VALIDITY_DAYS}; use serde::{Deserialize, Serialize}; use std::io; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; @@ -501,7 +501,7 @@ pub struct ZkNymTicketHandlerDebug { pub minimum_redemption_tickets: usize, /// Specifies the maximum time between two subsequent tickets redemptions. - /// That's required as nym-apis will purge all ticket information for tickets older than 30 days. + /// That's required as nym-apis will purge all ticket information for tickets older than maximum validity. #[serde(with = "humantime_serde")] pub maximum_time_between_redemption: Duration, } @@ -511,7 +511,28 @@ impl ZkNymTicketHandlerDebug { pub const DEFAULT_PENDING_POLLER: Duration = Duration::from_secs(300); pub const DEFAULT_MINIMUM_API_QUORUM: f32 = 0.8; pub const DEFAULT_MINIMUM_REDEMPTION_TICKETS: usize = 100; - pub const DEFAULT_MAXIMUM_TIME_BETWEEN_REDEMPTION: Duration = Duration::from_secs(86400 * 25); + + // use min(4/5 of max validity, validity - 1), but making sure it's no greater than 1 day + // ASSUMPTION: our validity period is AT LEAST 2 days + // + // this could have been a constant, but it's more readable as a function + pub const fn default_maximum_time_between_redemption() -> Duration { + let desired_secs = TICKETBOOK_VALIDITY_DAYS * (86400 * 4) / 5; + let desired_secs_alt = (TICKETBOOK_VALIDITY_DAYS - 1) * 86400; + + // can't use `min` in const context + let target_secs = if desired_secs < desired_secs_alt { + desired_secs + } else { + desired_secs_alt + }; + + assert!( + target_secs < 86400, + "the maximum time between redemption can't be lower than 1 day!" + ); + Duration::from_secs(target_secs as u64) + } } impl Default for ZkNymTicketHandlerDebug { @@ -521,7 +542,7 @@ impl Default for ZkNymTicketHandlerDebug { pending_poller: Self::DEFAULT_PENDING_POLLER, minimum_api_quorum: Self::DEFAULT_MINIMUM_API_QUORUM, minimum_redemption_tickets: Self::DEFAULT_MINIMUM_REDEMPTION_TICKETS, - maximum_time_between_redemption: Self::DEFAULT_MAXIMUM_TIME_BETWEEN_REDEMPTION, + maximum_time_between_redemption: Self::default_maximum_time_between_redemption(), } } } diff --git a/gateway/src/node/client_handling/websocket/connection_handler/ecash/credential_sender.rs b/gateway/src/node/client_handling/websocket/connection_handler/ecash/credential_sender.rs index 16670fe132..dcc1bb62bf 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/ecash/credential_sender.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/ecash/credential_sender.rs @@ -122,7 +122,7 @@ pub(crate) struct CredentialHandlerConfig { pub(crate) minimum_redemption_tickets: usize, /// Specifies the maximum time between two subsequent tickets redemptions. - /// That's required as nym-apis will purge all ticket information for tickets older than 30 days. + /// That's required as nym-apis will purge all ticket information for tickets older than maximum validity. pub(crate) maximum_time_between_redemption: Duration, } diff --git a/nym-api/src/ecash/state/helpers.rs b/nym-api/src/ecash/state/helpers.rs index ffcab88644..2fcfd18a31 100644 --- a/nym-api/src/ecash/state/helpers.rs +++ b/nym-api/src/ecash/state/helpers.rs @@ -56,7 +56,7 @@ pub(crate) async fn prepare_partial_bloomfilter_builder( .try_load_partial_bloomfilter_bitmap(date, params_id) .await? else { - log::warn!("missing double spending bloomfilter bitmap for {date} (if this API hasn't been running for at least 30 days since 'ecash'-based zk-nyms were introduced this is expected)"); + log::warn!("missing double spending bloomfilter bitmap for {date} (if this API hasn't been running for at least {days} day(s) since 'ecash'-based zk-nyms were introduced this is expected)"); continue; }; if !filter_builder.add_bytes(&bitmap) { diff --git a/nym-node/src/config/entry_gateway.rs b/nym-node/src/config/entry_gateway.rs index dd3670f42f..8a0144db71 100644 --- a/nym-node/src/config/entry_gateway.rs +++ b/nym-node/src/config/entry_gateway.rs @@ -5,7 +5,7 @@ use crate::config::helpers::ephemeral_gateway_config; use crate::config::persistence::EntryGatewayPaths; use crate::config::Config; use crate::error::EntryGatewayError; -use nym_config::defaults::DEFAULT_CLIENT_LISTENING_PORT; +use nym_config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, TICKETBOOK_VALIDITY_DAYS}; use nym_config::helpers::inaddr_any; use nym_config::serde_helpers::de_maybe_port; use nym_gateway::node::LocalAuthenticatorOpts; @@ -90,7 +90,7 @@ pub struct ZkNymTicketHandlerDebug { pub minimum_redemption_tickets: usize, /// Specifies the maximum time between two subsequent tickets redemptions. - /// That's required as nym-apis will purge all ticket information for tickets older than 30 days. + /// That's required as nym-apis will purge all ticket information for tickets older than maximum validity. #[serde(with = "humantime_serde")] pub maximum_time_between_redemption: Duration, } @@ -100,7 +100,28 @@ impl ZkNymTicketHandlerDebug { pub const DEFAULT_PENDING_POLLER: Duration = Duration::from_secs(300); pub const DEFAULT_MINIMUM_API_QUORUM: f32 = 0.8; pub const DEFAULT_MINIMUM_REDEMPTION_TICKETS: usize = 100; - pub const DEFAULT_MAXIMUM_TIME_BETWEEN_REDEMPTION: Duration = Duration::from_secs(86400 * 25); + + // use min(4/5 of max validity, validity - 1), but making sure it's no greater than 1 day + // ASSUMPTION: our validity period is AT LEAST 2 days + // + // this could have been a constant, but it's more readable as a function + pub const fn default_maximum_time_between_redemption() -> Duration { + let desired_secs = TICKETBOOK_VALIDITY_DAYS * (86400 * 4) / 5; + let desired_secs_alt = (TICKETBOOK_VALIDITY_DAYS - 1) * 86400; + + // can't use `min` in const context + let target_secs = if desired_secs < desired_secs_alt { + desired_secs + } else { + desired_secs_alt + }; + + assert!( + target_secs < 86400, + "the maximum time between redemption can't be lower than 1 day!" + ); + Duration::from_secs(target_secs as u64) + } } impl Default for ZkNymTicketHandlerDebug { @@ -110,7 +131,7 @@ impl Default for ZkNymTicketHandlerDebug { pending_poller: Self::DEFAULT_PENDING_POLLER, minimum_api_quorum: Self::DEFAULT_MINIMUM_API_QUORUM, minimum_redemption_tickets: Self::DEFAULT_MINIMUM_REDEMPTION_TICKETS, - maximum_time_between_redemption: Self::DEFAULT_MAXIMUM_TIME_BETWEEN_REDEMPTION, + maximum_time_between_redemption: Self::default_maximum_time_between_redemption(), } } } From 461b7bcfb70dab68cc99b2cf4f2336192db515ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 15:25:40 +0100 Subject: [PATCH 05/41] updated sandbox.env --- envs/sandbox.env | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/envs/sandbox.env b/envs/sandbox.env index 6deaafdfaa..4763269a6f 100644 --- a/envs/sandbox.env +++ b/envs/sandbox.env @@ -13,11 +13,10 @@ DENOMS_EXPONENT=6 REWARDING_VALIDATOR_ADDRESS=n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa MIXNET_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav VESTING_CONTRACT_ADDRESS=n1unyuj8qnmygvzuex3dwmg9yzt9alhvyeat0uu0jedg2wj33efl5qackslz -ECASH_CONTRACT_ADDRESS=n1ljlwey4xdj0zs7zueepc48nkr033fca6fjgvurfvttqegm8dvsrswsul70 -GROUP_CONTRACT_ADDRESS=n10v3rjnq4cjyccfykyams68ztce337gksuu6f0lvtl4meuwvkewaqru4uav -MULTISIG_CONTRACT_ADDRESS=n1cemnu8as0ls45v3caunpesl8jlsfw2ff9rlwnltlecp7zrxct4dsqc2y42 -COCONUT_DKG_CONTRACT_ADDRESS=n1zx96qgd88vqlzcxkpwzks7kqs5ctrx36xtzfc58p7q6c4ng9anlqzc4nh8 - +GROUP_CONTRACT_ADDRESS=n1ewmwz97xm0h8rdk8sw7h9mwn866qkx9hl9zlmagqfkhuzvwk5hhq844ue9 +MULTISIG_CONTRACT_ADDRESS=n1tz0setr8vkh9udp8xyxgpqc89ns27k4d0jx2h942hr0ax63yjhmqz6xct8 +COCONUT_DKG_CONTRACT_ADDRESS=n1v3n2ly2dp3a9ng3ff6rh26yfkn0pc5hed7w2shc5u9ca5c865utqj5elvh +ECASH_CONTRACT_ADDRESS=n1v3vydvs2ued84yv3khqwtgldmgwn0elljsdh08dr5s2j9x4rc5fs9jlwz9 STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0" EXPLORER_API=https://sandbox-explorer.nymtech.net/api From e3e4dc6db9bbe5bb435bb3c2c1768717c64f9698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 16:31:00 +0100 Subject: [PATCH 06/41] added an utility nym-cli command to output binary representation of ecash tickets --- Cargo.lock | 286 +++++------------- .../bandwidth-controller/src/acquire/mod.rs | 10 +- common/bandwidth-controller/src/lib.rs | 6 +- common/commands/Cargo.toml | 9 +- common/commands/src/ecash/generate_ticket.rs | 177 +++++++++++ .../{coconut => ecash}/import_ticket_book.rs | 0 .../{coconut => ecash}/issue_ticket_book.rs | 52 +++- common/commands/src/{coconut => ecash}/mod.rs | 2 + .../{coconut => ecash}/recover_ticket_book.rs | 0 common/commands/src/lib.rs | 2 +- .../mixnode/keys/decode_mixnode_key.rs | 6 +- common/credential-utils/src/utils.rs | 16 +- .../credentials/src/ecash/bandwidth/issued.rs | 6 +- sdk/rust/nym-sdk/src/bandwidth/client.rs | 4 +- sdk/rust/nym-sdk/src/mixnet/client.rs | 26 +- tools/nym-cli/src/coconut/mod.rs | 29 -- tools/nym-cli/src/ecash/mod.rs | 32 ++ tools/nym-cli/src/main.rs | 6 +- 18 files changed, 385 insertions(+), 284 deletions(-) create mode 100644 common/commands/src/ecash/generate_ticket.rs rename common/commands/src/{coconut => ecash}/import_ticket_book.rs (100%) rename common/commands/src/{coconut => ecash}/issue_ticket_book.rs (52%) rename common/commands/src/{coconut => ecash}/mod.rs (89%) rename common/commands/src/{coconut => ecash}/recover_ticket_book.rs (100%) delete mode 100644 tools/nym-cli/src/coconut/mod.rs create mode 100644 tools/nym-cli/src/ecash/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 0923a3a4f9..ad525671a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,15 +332,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.3.0", -] - [[package]] name = "autocfg" version = "1.3.0" @@ -553,7 +544,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", + "rand", "rand_core 0.6.4", "serde", "unicode-normalization", @@ -994,15 +985,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "colorchoice" version = "1.0.1" @@ -2259,8 +2241,8 @@ dependencies = [ "nym-validator-client", "okapi", "pretty_env_logger", - "rand 0.8.5", - "rand_pcg 0.3.1", + "rand", + "rand_pcg", "rand_seeder", "reqwest 0.12.4", "rocket", @@ -2459,12 +2441,6 @@ dependencies = [ "libc", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "funty" version = "2.0.0" @@ -3345,7 +3321,7 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "autocfg 1.3.0", + "autocfg", "hashbrown 0.12.3", "serde", ] @@ -3760,7 +3736,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ - "autocfg 1.3.0", + "autocfg", "scopeguard", ] @@ -3887,7 +3863,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ - "autocfg 1.3.0", + "autocfg", ] [[package]] @@ -3957,7 +3933,7 @@ dependencies = [ "nym-ordered-buffer", "nym-service-providers-common", "nym-socks5-requests", - "rand 0.8.5", + "rand", "serde", "serde-wasm-bindgen 0.6.5", "thiserror", @@ -4173,7 +4149,7 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "autocfg 1.3.0", + "autocfg", "libm", ] @@ -4257,8 +4233,8 @@ dependencies = [ "nym-vesting-contract-common", "okapi", "pin-project", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "reqwest 0.12.4", "rocket", "rocket_cors", @@ -4344,7 +4320,7 @@ dependencies = [ "nym-types", "nym-wireguard", "nym-wireguard-types", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror", @@ -4361,7 +4337,7 @@ dependencies = [ "bincode", "nym-sphinx", "nym-wireguard-types", - "rand 0.8.5", + "rand", "serde", ] @@ -4379,7 +4355,7 @@ dependencies = [ "nym-ecash-time", "nym-network-defaults", "nym-validator-client", - "rand 0.8.5", + "rand", "thiserror", "url", "zeroize", @@ -4453,11 +4429,12 @@ name = "nym-cli-commands" version = "1.0.0" dependencies = [ "anyhow", - "base64 0.13.1", + "base64 0.21.7", "bip39", "bs58 0.5.1", "cfg-if", "clap 4.5.7", + "colored", "comfy-table 6.2.0", "cosmrs 0.17.0-pre", "cosmwasm-std", @@ -4490,14 +4467,14 @@ dependencies = [ "nym-types", "nym-validator-client", "nym-vesting-contract-common", - "rand 0.6.5", + "rand", "serde", "serde_json", "tap", "thiserror", "time", "tokio", - "toml 0.5.11", + "toml 0.8.14", "url", "zeroize", ] @@ -4527,7 +4504,7 @@ dependencies = [ "nym-task", "nym-topology", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "serde_json", "tap", @@ -4578,7 +4555,7 @@ dependencies = [ "nym-task", "nym-topology", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "serde_json", "sha2 0.10.8", @@ -4658,7 +4635,7 @@ dependencies = [ "nym-bin-common", "nym-node-tester-utils", "nym-node-tester-wasm", - "rand 0.8.5", + "rand", "serde", "serde-wasm-bindgen 0.6.5", "serde_json", @@ -4695,8 +4672,8 @@ dependencies = [ "itertools 0.13.0", "nym-dkg", "nym-pemstore", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "serde", "serde_derive", "sha2 0.9.9", @@ -4742,7 +4719,7 @@ dependencies = [ "itertools 0.12.1", "nym-network-defaults", "nym-pemstore", - "rand 0.8.5", + "rand", "rayon", "serde", "sha2 0.9.9", @@ -4836,7 +4813,7 @@ dependencies = [ "nym-ecash-time", "nym-network-defaults", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "thiserror", "time", @@ -4851,7 +4828,7 @@ dependencies = [ "nym-compact-ecash", "nym-ecash-time", "nym-network-defaults", - "rand 0.8.5", + "rand", "serde", "strum 0.25.0", "thiserror", @@ -4874,8 +4851,8 @@ dependencies = [ "hmac", "nym-pemstore", "nym-sphinx-types", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "serde", "serde_bytes", "subtle-encoding", @@ -4897,8 +4874,8 @@ dependencies = [ "lazy_static", "nym-contracts-common", "nym-pemstore", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "rand_core 0.6.4", "serde", "serde_derive", @@ -5028,7 +5005,7 @@ dependencies = [ "nym-wireguard", "nym-wireguard-types", "once_cell", - "rand 0.8.5", + "rand", "serde", "serde_json", "si-scale", @@ -5063,7 +5040,7 @@ dependencies = [ "nym-sphinx", "nym-task", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "si-scale", "thiserror", @@ -5092,7 +5069,7 @@ dependencies = [ "nym-crypto", "nym-pemstore", "nym-sphinx", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror", @@ -5192,7 +5169,7 @@ name = "nym-inclusion-probability" version = "0.1.0" dependencies = [ "log", - "rand 0.8.5", + "rand", "thiserror", ] @@ -5205,7 +5182,7 @@ dependencies = [ "nym-bin-common", "nym-crypto", "nym-sphinx", - "rand 0.8.5", + "rand", "serde", "thiserror", "time", @@ -5242,7 +5219,7 @@ dependencies = [ "nym-types", "nym-wireguard", "nym-wireguard-types", - "rand 0.8.5", + "rand", "reqwest 0.12.4", "serde", "serde_json", @@ -5299,7 +5276,7 @@ dependencies = [ "humantime-serde", "log", "nym-contracts-common", - "rand_chacha 0.3.1", + "rand_chacha", "schemars", "serde", "serde-json-wasm", @@ -5342,7 +5319,7 @@ dependencies = [ "nym-topology", "nym-types", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "serde_json", "sysinfo 0.27.8", @@ -5375,7 +5352,7 @@ dependencies = [ "nym-sphinx-types", "nym-task", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "thiserror", "time", @@ -5445,7 +5422,7 @@ dependencies = [ "nym-types", "pretty_env_logger", "publicsuffix", - "rand 0.8.5", + "rand", "regex", "reqwest 0.12.4", "serde", @@ -5492,7 +5469,7 @@ dependencies = [ "nym-types", "nym-wireguard", "nym-wireguard-types", - "rand 0.8.5", + "rand", "semver 1.0.23", "serde", "serde_json", @@ -5526,7 +5503,7 @@ dependencies = [ "nym-task", "nym-wireguard", "nym-wireguard-types", - "rand 0.8.5", + "rand", "serde_json", "thiserror", "time", @@ -5553,7 +5530,7 @@ dependencies = [ "nym-exit-policy", "nym-http-api-client", "nym-wireguard-types", - "rand_chacha 0.3.1", + "rand_chacha", "schemars", "serde", "serde_json", @@ -5574,7 +5551,7 @@ dependencies = [ "nym-sphinx-params", "nym-task", "nym-topology", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror", @@ -5589,7 +5566,7 @@ dependencies = [ "futures", "js-sys", "nym-node-tester-utils", - "rand 0.8.5", + "rand", "serde", "serde-wasm-bindgen 0.6.5", "thiserror", @@ -5648,7 +5625,7 @@ dependencies = [ "fastrand 2.1.0", "getrandom", "log", - "rand 0.8.5", + "rand", "rayon", "sphinx-packet", "thiserror", @@ -5697,7 +5674,7 @@ dependencies = [ "nym-validator-client", "parking_lot 0.12.3", "pretty_env_logger", - "rand 0.8.5", + "rand", "reqwest 0.12.4", "tap", "thiserror", @@ -5757,7 +5734,7 @@ dependencies = [ "nym-sphinx", "nym-topology", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "serde_json", "tap", @@ -5790,7 +5767,7 @@ dependencies = [ "nym-task", "nym-validator-client", "pin-project", - "rand 0.8.5", + "rand", "reqwest 0.12.4", "schemars", "serde", @@ -5816,7 +5793,7 @@ dependencies = [ "nym-credential-storage", "nym-crypto", "nym-socks5-client-core", - "rand 0.8.5", + "rand", "safer-ffi", "serde", "tokio", @@ -5870,7 +5847,7 @@ dependencies = [ "nym-sphinx-routing", "nym-sphinx-types", "nym-topology", - "rand 0.8.5", + "rand", "rand_distr", "thiserror", "tokio", @@ -5888,7 +5865,7 @@ dependencies = [ "nym-sphinx-routing", "nym-sphinx-types", "nym-topology", - "rand 0.8.5", + "rand", "serde", "thiserror", "zeroize", @@ -5900,7 +5877,7 @@ version = "0.1.0" dependencies = [ "nym-crypto", "nym-sphinx-types", - "rand 0.8.5", + "rand", "serde", "thiserror", ] @@ -5916,8 +5893,8 @@ dependencies = [ "nym-sphinx-routing", "nym-sphinx-types", "nym-topology", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "serde", "thiserror", "wasm-bindgen", @@ -5931,7 +5908,7 @@ dependencies = [ "nym-sphinx-addressing", "nym-sphinx-params", "nym-sphinx-types", - "rand 0.8.5", + "rand", "thiserror", ] @@ -5948,7 +5925,7 @@ dependencies = [ "nym-sphinx-routing", "nym-sphinx-types", "nym-topology", - "rand 0.8.5", + "rand", "thiserror", ] @@ -6010,7 +5987,7 @@ dependencies = [ "argon2", "generic-array 0.14.7", "getrandom", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror", @@ -6045,7 +6022,7 @@ dependencies = [ "nym-sphinx-addressing", "nym-sphinx-routing", "nym-sphinx-types", - "rand 0.8.5", + "rand", "semver 0.11.0", "serde", "serde_json", @@ -6169,7 +6146,7 @@ dependencies = [ "nym-task", "nym-validator-client", "nyxd-scraper", - "rand_chacha 0.3.1", + "rand_chacha", "serde", "serde_with", "sha2 0.10.8", @@ -6248,7 +6225,7 @@ dependencies = [ "nym-config", "nym-crypto", "nym-network-defaults", - "rand 0.8.5", + "rand", "serde", "serde_json", "sha2 0.10.8", @@ -6458,7 +6435,7 @@ dependencies = [ "once_cell", "opentelemetry_api", "percent-encoding", - "rand 0.8.5", + "rand", "thiserror", "tokio", "tokio-stream", @@ -6771,7 +6748,7 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ - "autocfg 1.3.0", + "autocfg", "bitflags 1.3.2", "cfg-if", "concurrent-queue", @@ -7025,25 +7002,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg 0.1.2", - "rand_xorshift", - "winapi", -] - [[package]] name = "rand" version = "0.8.5" @@ -7051,20 +7009,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", + "rand_chacha", "rand_core 0.6.4", ] -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -7075,21 +7023,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.5.1" @@ -7112,60 +7045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", + "rand", ] [[package]] @@ -7186,15 +7066,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "rayon" version = "1.10.0" @@ -7215,15 +7086,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -7481,7 +7343,7 @@ dependencies = [ "num_cpus", "parking_lot 0.12.3", "pin-project-lite", - "rand 0.8.5", + "rand", "ref-cast", "rocket_codegen", "rocket_http", @@ -8254,7 +8116,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "autocfg 1.3.0", + "autocfg", ] [[package]] @@ -8325,7 +8187,7 @@ dependencies = [ "hmac", "lioness", "log", - "rand 0.8.5", + "rand", "rand_distr", "sha2 0.10.8", "subtle 2.5.0", @@ -8869,7 +8731,7 @@ dependencies = [ "getrandom", "peg", "pin-project", - "rand 0.8.5", + "rand", "reqwest 0.11.27", "semver 1.0.23", "serde", @@ -8923,7 +8785,7 @@ dependencies = [ "nym-pemstore", "nym-validator-client", "nym-vesting-contract-common", - "rand 0.8.5", + "rand", "serde", "serde_json", "sqlx", @@ -9323,7 +9185,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand 0.8.5", + "rand", "slab", "tokio", "tokio-util", @@ -9589,7 +9451,7 @@ dependencies = [ "http 0.2.12", "httparse", "log", - "rand 0.8.5", + "rand", "rustls 0.21.12", "sha1", "thiserror", @@ -9610,7 +9472,7 @@ dependencies = [ "http 1.1.0", "httparse", "log", - "rand 0.8.5", + "rand", "rustls 0.22.4", "rustls-pki-types", "sha1", @@ -10030,7 +9892,7 @@ dependencies = [ "nym-task", "nym-topology", "nym-validator-client", - "rand 0.8.5", + "rand", "serde", "serde-wasm-bindgen 0.6.5", "thiserror", @@ -10665,7 +10527,7 @@ dependencies = [ "nym-credentials", "nym-crypto", "nym-http-api-client", - "rand 0.8.5", + "rand", "reqwest 0.12.4", "serde", "thiserror", diff --git a/common/bandwidth-controller/src/acquire/mod.rs b/common/bandwidth-controller/src/acquire/mod.rs index 51afe221fe..e2d18d5545 100644 --- a/common/bandwidth-controller/src/acquire/mod.rs +++ b/common/bandwidth-controller/src/acquire/mod.rs @@ -2,7 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BandwidthControllerError; -use crate::utils::{get_coin_index_signatures, get_expiration_date_signatures}; +use crate::utils::{ + get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures, +}; use log::info; use nym_credential_storage::storage::Storage; use nym_credentials::ecash::bandwidth::IssuanceTicketBook; @@ -55,7 +57,7 @@ where )) } -pub async fn query_and_persist_required_global_signatures( +pub async fn query_and_persist_required_global_data( storage: &S, epoch_id: EpochId, expiration_date: Date, @@ -65,6 +67,10 @@ where S: 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?; diff --git a/common/bandwidth-controller/src/lib.rs b/common/bandwidth-controller/src/lib.rs index 4485009b68..a164d3df60 100644 --- a/common/bandwidth-controller/src/lib.rs +++ b/common/bandwidth-controller/src/lib.rs @@ -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, NymPayInfo, VerificationKeyAuth, + AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth, }; use nym_ecash_time::Date; use nym_validator_client::nym_api::EpochId; @@ -165,7 +165,9 @@ impl BandwidthController { .get_coin_index_signatures(epoch_id, &mut api_clients) .await?; - let pay_info = NymPayInfo::generate(provider_pk); + let pay_info = retrieved_ticketbook + .ticketbook + .generate_pay_info(provider_pk); let spend_request = retrieved_ticketbook.ticketbook.prepare_for_spending( &verification_key, diff --git a/common/commands/Cargo.toml b/common/commands/Cargo.toml index 2045cf0d2a..6ff825dcbc 100644 --- a/common/commands/Cargo.toml +++ b/common/commands/Cargo.toml @@ -7,9 +7,10 @@ license.workspace = true [dependencies] anyhow = { workspace = true } -base64 = "0.13.0" +base64 = { workspace = true } bip39 = { workspace = true } bs58 = { workspace = true } +colored = { workspace = true } comfy-table = { workspace = true } cfg-if = { workspace = true } clap = { workspace = true, features = ["derive"] } @@ -21,13 +22,13 @@ humantime-serde = { workspace = true } inquire = { workspace = true } k256 = { workspace = true, features = ["ecdsa", "sha256"] } log = { workspace = true } -rand = {version = "0.6", features = ["std"] } +rand = { workspace = true, 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 = "0.5.6" +tokio = { workspace = true, features = ["sync"] } +toml = { workspace = true } url = { workspace = true } tap = { workspace = true } zeroize = { workspace = true } diff --git a/common/commands/src/ecash/generate_ticket.rs b/common/commands/src/ecash/generate_ticket.rs new file mode 100644 index 0000000000..1300560931 --- /dev/null +++ b/common/commands/src/ecash/generate_ticket.rs @@ -0,0 +1,177 @@ +// Copyright 2024 - Nym Technologies SA +// 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, + + /// 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, + + /// Path to the dedicated credential storage database + #[clap(long, group = "source")] + pub(crate) credential_storage: Option, +} + +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()); + } + + 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(()) +} diff --git a/common/commands/src/coconut/import_ticket_book.rs b/common/commands/src/ecash/import_ticket_book.rs similarity index 100% rename from common/commands/src/coconut/import_ticket_book.rs rename to common/commands/src/ecash/import_ticket_book.rs diff --git a/common/commands/src/coconut/issue_ticket_book.rs b/common/commands/src/ecash/issue_ticket_book.rs similarity index 52% rename from common/commands/src/coconut/issue_ticket_book.rs rename to common/commands/src/ecash/issue_ticket_book.rs index c6b0997ba5..eb63f7b322 100644 --- a/common/commands/src/coconut/issue_ticket_book.rs +++ b/common/commands/src/ecash/issue_ticket_book.rs @@ -9,6 +9,9 @@ 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)] @@ -18,12 +21,20 @@ pub struct Args { pub(crate) ticketbook_type: TicketType, /// Config file of the client that is supposed to use the credential. - #[clap(long)] - pub(crate) client_config: PathBuf, + #[clap(long, group = "output")] + pub(crate) client_config: Option, + + /// Path to the dedicated credential storage database + #[clap(long, group = "output")] + pub(crate) credential_storage: Option, } -pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> { - let loaded = CommonConfigsWrapper::try_load(args.client_config)?; +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}'"); @@ -48,9 +59,40 @@ pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> { &client, &persistent_storage, &private_id_key.to_bytes(), - args.ticketbook_type, + 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!"), + } +} diff --git a/common/commands/src/coconut/mod.rs b/common/commands/src/ecash/mod.rs similarity index 89% rename from common/commands/src/coconut/mod.rs rename to common/commands/src/ecash/mod.rs index 74421dd42b..77ca858366 100644 --- a/common/commands/src/coconut/mod.rs +++ b/common/commands/src/ecash/mod.rs @@ -3,6 +3,7 @@ use clap::{Args, Subcommand}; +pub mod generate_ticket; pub mod import_ticket_book; pub mod issue_ticket_book; pub mod recover_ticket_book; @@ -19,4 +20,5 @@ pub enum EcashCommands { IssueTicketBook(issue_ticket_book::Args), RecoverTicketBook(recover_ticket_book::Args), ImportTicketBook(import_ticket_book::Args), + GenerateTicket(generate_ticket::Args), } diff --git a/common/commands/src/coconut/recover_ticket_book.rs b/common/commands/src/ecash/recover_ticket_book.rs similarity index 100% rename from common/commands/src/coconut/recover_ticket_book.rs rename to common/commands/src/ecash/recover_ticket_book.rs diff --git a/common/commands/src/lib.rs b/common/commands/src/lib.rs index afca2be0f7..e3670ac572 100644 --- a/common/commands/src/lib.rs +++ b/common/commands/src/lib.rs @@ -1,7 +1,7 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub mod coconut; pub mod context; +pub mod ecash; pub mod utils; pub mod validator; diff --git a/common/commands/src/validator/mixnet/operators/mixnode/keys/decode_mixnode_key.rs b/common/commands/src/validator/mixnet/operators/mixnode/keys/decode_mixnode_key.rs index 21b026c85e..fc16a067d2 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/keys/decode_mixnode_key.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/keys/decode_mixnode_key.rs @@ -10,7 +10,11 @@ pub struct Args { } pub fn decode_mixnode_key(args: Args) { - let b64_decoded = base64::decode(args.key).expect("failed to decode base64 string"); + use base64::{engine::general_purpose::STANDARD, Engine as _}; + + let b64_decoded = STANDARD + .decode(args.key) + .expect("failed to decode base64 string"); let b58_encoded = bs58::encode(&b64_decoded).into_string(); println!("{b58_encoded}") diff --git a/common/credential-utils/src/utils.rs b/common/credential-utils/src/utils.rs index 41381d53f9..be7133b4c2 100644 --- a/common/credential-utils/src/utils.rs +++ b/common/credential-utils/src/utils.rs @@ -3,9 +3,7 @@ use crate::errors::{Error, Result}; use log::*; -use nym_bandwidth_controller::acquire::{ - get_ticket_book, query_and_persist_required_global_signatures, -}; +use nym_bandwidth_controller::acquire::{get_ticket_book, query_and_persist_required_global_data}; use nym_client_core::config::disk_persistence::CommonClientPaths; use nym_config::DEFAULT_DATA_DIR; use nym_credential_storage::persistent_storage::PersistentStorage; @@ -45,14 +43,10 @@ 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 before attempting the deposit - query_and_persist_required_global_signatures( - storage, - epoch_id, - ticketbook_expiration, - apis.clone(), - ) - .await?; + // 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?; let issuance_data = nym_bandwidth_controller::acquire::make_deposit( client, diff --git a/common/credentials/src/ecash/bandwidth/issued.rs b/common/credentials/src/ecash/bandwidth/issued.rs index 8787528ae4..da04d38620 100644 --- a/common/credentials/src/ecash/bandwidth/issued.rs +++ b/common/credentials/src/ecash/bandwidth/issued.rs @@ -6,7 +6,7 @@ use crate::ecash::bandwidth::CredentialSpendingData; use crate::ecash::utils::ecash_today; use crate::error::Error; use nym_credentials_interface::{ - CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, TicketType, + CoinIndexSignature, ExpirationDateSignature, NymPayInfo, PayInfo, SecretKeyUser, TicketType, VerificationKeyAuth, Wallet, WalletSignatures, }; use nym_ecash_time::EcashTime; @@ -114,6 +114,10 @@ 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( &mut self, verification_key: &VerificationKeyAuth, diff --git a/sdk/rust/nym-sdk/src/bandwidth/client.rs b/sdk/rust/nym-sdk/src/bandwidth/client.rs index 19da50eccb..785f1b5fc0 100644 --- a/sdk/rust/nym-sdk/src/bandwidth/client.rs +++ b/sdk/rust/nym-sdk/src/bandwidth/client.rs @@ -17,7 +17,7 @@ use zeroize::Zeroizing; pub struct BandwidthAcquireClient<'a, St: Storage> { client: DirectSigningHttpRpcNyxdClient, storage: &'a St, - client_id: Zeroizing, + client_id: Zeroizing>, ticketbook_type: TicketType, } @@ -30,7 +30,7 @@ where network_details: NymNetworkDetails, mnemonic: String, storage: &'a St, - client_id: String, + client_id: Vec, ticketbook_type: TicketType, ) -> Result { let nyxd_url = network_details.endpoints[0].nyxd_url.as_str(); diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index 7d26b1f9aa..19048f5005 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -40,6 +40,7 @@ use std::net::IpAddr; use std::path::Path; use std::path::PathBuf; use url::Url; +use zeroize::Zeroizing; // The number of surbs to include in a message by default const DEFAULT_NUMBER_OF_SURBS: u32 = 10; @@ -560,17 +561,20 @@ where if !self.config.enabled_credentials_mode { return Err(Error::DisabledCredentialsMode); } - let client_id = self - .storage - .key_store() - .load_keys() - .await - .map_err(|e| Error::KeyStorageError { - source: Box::new(e), - })? - .identity_keypair() - .private_key() - .to_base58_string(); + let client_id_array = Zeroizing::new( + self.storage + .key_store() + .load_keys() + .await + .map_err(|e| Error::KeyStorageError { + source: Box::new(e), + })? + .identity_keypair() + .private_key() + .to_bytes(), + ); + let client_id = client_id_array.to_vec(); + BandwidthAcquireClient::new( self.config.network_details.clone(), mnemonic, diff --git a/tools/nym-cli/src/coconut/mod.rs b/tools/nym-cli/src/coconut/mod.rs deleted file mode 100644 index 6fda72e6a0..0000000000 --- a/tools/nym-cli/src/coconut/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -use nym_cli_commands::context::{create_query_client, create_signing_client, ClientArgs}; -use nym_network_defaults::NymNetworkDetails; - -pub(crate) async fn execute( - global_args: ClientArgs, - coconut: nym_cli_commands::coconut::Ecash, - network_details: &NymNetworkDetails, -) -> anyhow::Result<()> { - match coconut.command { - nym_cli_commands::coconut::EcashCommands::IssueTicketBook(args) => { - nym_cli_commands::coconut::issue_ticket_book::execute( - args, - create_signing_client(global_args, network_details)?, - ) - .await? - } - nym_cli_commands::coconut::EcashCommands::RecoverTicketBook(args) => { - nym_cli_commands::coconut::recover_ticket_book::execute( - args, - create_query_client(network_details)?, - ) - .await? - } - nym_cli_commands::coconut::EcashCommands::ImportTicketBook(args) => { - nym_cli_commands::coconut::import_ticket_book::execute(args).await? - } - } - Ok(()) -} diff --git a/tools/nym-cli/src/ecash/mod.rs b/tools/nym-cli/src/ecash/mod.rs new file mode 100644 index 0000000000..1cc3d00020 --- /dev/null +++ b/tools/nym-cli/src/ecash/mod.rs @@ -0,0 +1,32 @@ +use nym_cli_commands::context::{create_query_client, create_signing_client, ClientArgs}; +use nym_network_defaults::NymNetworkDetails; + +pub(crate) async fn execute( + global_args: ClientArgs, + coconut: nym_cli_commands::ecash::Ecash, + network_details: &NymNetworkDetails, +) -> anyhow::Result<()> { + match coconut.command { + nym_cli_commands::ecash::EcashCommands::IssueTicketBook(args) => { + nym_cli_commands::ecash::issue_ticket_book::execute( + args, + create_signing_client(global_args, network_details)?, + ) + .await? + } + nym_cli_commands::ecash::EcashCommands::RecoverTicketBook(args) => { + nym_cli_commands::ecash::recover_ticket_book::execute( + args, + create_query_client(network_details)?, + ) + .await? + } + nym_cli_commands::ecash::EcashCommands::ImportTicketBook(args) => { + nym_cli_commands::ecash::import_ticket_book::execute(args).await? + } + nym_cli_commands::ecash::EcashCommands::GenerateTicket(args) => { + nym_cli_commands::ecash::generate_ticket::execute(args).await? + } + } + Ok(()) +} diff --git a/tools/nym-cli/src/main.rs b/tools/nym-cli/src/main.rs index 12defe4817..c5b4cc51e3 100644 --- a/tools/nym-cli/src/main.rs +++ b/tools/nym-cli/src/main.rs @@ -7,8 +7,8 @@ use nym_bin_common::logging::setup_logging; use nym_cli_commands::context::{get_network_details, ClientArgs}; use nym_validator_client::nyxd::AccountId; -mod coconut; mod completion; +mod ecash; mod validator; #[derive(Debug, Parser)] @@ -63,7 +63,7 @@ pub(crate) enum Commands { /// Sign and verify messages Signature(nym_cli_commands::validator::signature::Signature), /// Ecash related stuff - Ecash(nym_cli_commands::coconut::Ecash), + Ecash(nym_cli_commands::ecash::Ecash), /// Query chain blocks Block(nym_cli_commands::validator::block::Block), /// Manage and execute WASM smart contracts @@ -104,7 +104,7 @@ async fn execute(cli: Cli) -> anyhow::Result<()> { Commands::Signature(signature) => { validator::signature::execute(signature, &network_details, mnemonic).await? } - Commands::Ecash(coconut) => coconut::execute(args, coconut, &network_details).await?, + Commands::Ecash(coconut) => ecash::execute(args, coconut, &network_details).await?, Commands::Block(block) => validator::block::execute(block, &network_details).await?, Commands::Cosmwasm(cosmwasm) => { validator::cosmwasm::execute(args, cosmwasm, &network_details).await? From eeeb4b32464d271931a928af7dc1b22720c78202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 16:43:36 +0100 Subject: [PATCH 07/41] fixed incorrect assertion when validating maximum time between redemption --- gateway/src/config/mod.rs | 2 +- nym-node/src/config/entry_gateway.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index 5a5c57e3f9..7605987a79 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -528,7 +528,7 @@ impl ZkNymTicketHandlerDebug { }; assert!( - target_secs < 86400, + target_secs > 86400, "the maximum time between redemption can't be lower than 1 day!" ); Duration::from_secs(target_secs as u64) diff --git a/nym-node/src/config/entry_gateway.rs b/nym-node/src/config/entry_gateway.rs index 8a0144db71..6807e55d58 100644 --- a/nym-node/src/config/entry_gateway.rs +++ b/nym-node/src/config/entry_gateway.rs @@ -117,7 +117,7 @@ impl ZkNymTicketHandlerDebug { }; assert!( - target_secs < 86400, + target_secs > 86400, "the maximum time between redemption can't be lower than 1 day!" ); Duration::from_secs(target_secs as u64) From b5eab7f07f9b0d2734a8c61f7ac7544ab17ad9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Tue, 20 Aug 2024 17:49:27 +0200 Subject: [PATCH 08/41] Better storage error logging (#4772) * Better storage error logging * Print without including error returned to clients --- .../client_handling/websocket/connection_handler/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gateway/src/node/client_handling/websocket/connection_handler/mod.rs b/gateway/src/node/client_handling/websocket/connection_handler/mod.rs index ecb0aa48d7..656ac91c65 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/mod.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/mod.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::config::Config; +use fresh::InitialAuthenticationError; use nym_credentials_interface::AvailableBandwidth; use nym_gateway_requests::registration::handshake::SharedKeys; use nym_gateway_requests::ServerResponse; @@ -122,6 +123,12 @@ pub(crate) async fn handle_connection( trace!("received shutdown signal while performing initial authentication"); return; } + // For storage error, we want to print the extended storage error, but without + // including it in the error that's returned to the clients + Some(Err(InitialAuthenticationError::StorageError(err))) => { + warn!("authentication has failed: {err}"); + return; + } Some(Err(err)) => { warn!("authentication has failed: {err}"); return; From 776443131eb7ee9198b6c27d0b17c282249aa553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 16:57:18 +0100 Subject: [PATCH 09/41] fixed full display being always printed --- common/commands/src/ecash/generate_ticket.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/commands/src/ecash/generate_ticket.rs b/common/commands/src/ecash/generate_ticket.rs index 1300560931..67a85ab093 100644 --- a/common/commands/src/ecash/generate_ticket.rs +++ b/common/commands/src/ecash/generate_ticket.rs @@ -124,6 +124,7 @@ pub async fn execute(args: Args) -> anyhow::Result<()> { println!("{}", format!("PAYMENT FOR TICKET {next_ticket}: ").bold()); println!("{}", bs58::encode(&payment.to_bytes()).into_string()); + return Ok(()); } println!( From f40c05a34c0b13f60b7d3c5b5568446feb188705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 20 Aug 2024 17:01:41 +0100 Subject: [PATCH 10/41] fixed incorrect propagation of client_id in the sdk --- sdk/rust/nym-sdk/src/bandwidth/client.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/rust/nym-sdk/src/bandwidth/client.rs b/sdk/rust/nym-sdk/src/bandwidth/client.rs index 785f1b5fc0..3f5acbd5e9 100644 --- a/sdk/rust/nym-sdk/src/bandwidth/client.rs +++ b/sdk/rust/nym-sdk/src/bandwidth/client.rs @@ -7,6 +7,7 @@ use nym_credential_utils::utils::issue_credential; use nym_credentials_interface::TicketType; use nym_network_defaults::NymNetworkDetails; use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient}; +use std::ops::Deref; use zeroize::Zeroizing; /// Represents a client that can be used to acquire bandwidth. You typically create one when you @@ -53,7 +54,7 @@ where issue_credential( &self.client, self.storage, - self.client_id.as_bytes(), + self.client_id.deref(), self.ticketbook_type, ) .await?; From a6ad6c7d491b4f52d6d833e39e0f0d164fc5ebe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Wed, 21 Aug 2024 14:17:01 +0200 Subject: [PATCH 11/41] Sync last_seen_bandwidth immediately (#4774) --- common/wireguard/src/peer_controller.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/wireguard/src/peer_controller.rs b/common/wireguard/src/peer_controller.rs index 7a48a20857..ad7628c8b8 100644 --- a/common/wireguard/src/peer_controller.rs +++ b/common/wireguard/src/peer_controller.rs @@ -64,14 +64,19 @@ impl PeerController { let timeout_check_interval = tokio_stream::wrappers::IntervalStream::new( tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK), ); - let active_peers = peers + let active_peers: HashMap = peers .into_iter() .map(|peer| (peer.public_key.clone(), peer)) .collect(); - let suspended_peers = suspended_peers + let suspended_peers: HashMap = suspended_peers .into_iter() .map(|peer| (peer.public_key.clone(), peer)) .collect(); + let last_seen_bandwidth = active_peers + .iter() + .map(|(k, p)| (k.clone(), p.rx_bytes + p.tx_bytes)) + .chain(suspended_peers.keys().map(|k| (k.clone(), 0))) + .collect(); PeerController { storage, @@ -81,7 +86,7 @@ impl PeerController { timeout_check_interval, active_peers, suspended_peers, - last_seen_bandwidth: HashMap::new(), + last_seen_bandwidth, } } @@ -192,6 +197,7 @@ impl PeerController { log::error!("Could not configure peer: {:?}", e); false } else { + self.last_seen_bandwidth.insert(peer.public_key.clone(), peer.rx_bytes + peer.tx_bytes); self.active_peers.insert(peer.public_key.clone(), peer); true }; From 3238722ade1b3d19b794edfa74f31f7addc4aa73 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 27 Aug 2024 14:55:47 +0200 Subject: [PATCH 12/41] WIP --- .../mixnode/settings/update_cost_params.rs | 35 ++++++++++++++----- .../mixnet/operators/mixnodes/settings/mod.rs | 2 +- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs index 0616a81d33..2b64dbfdf4 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs @@ -5,15 +5,15 @@ use crate::context::SigningClient; use clap::Parser; use cosmwasm_std::Uint128; use log::info; -use nym_mixnet_contract_common::{MixNodeCostParams, Percent}; -use nym_validator_client::nyxd::contract_traits::MixnetSigningClient; +use nym_mixnet_contract_common::{MixId, MixNodeCostParams, Percent}; +use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; use nym_validator_client::nyxd::CosmWasmCoin; #[derive(Debug, Parser)] pub struct Args { #[clap( long, - help = "input your profit margin as follows; (so it would be 10, rather than 0.1)" + help = "input your profit margin as follows; (so it would be 20, rather than 0.2)" )] pub profit_margin_percent: Option, @@ -24,14 +24,33 @@ pub struct Args { pub interval_operating_cost: Option, } -pub async fn update_cost_params(args: Args, client: SigningClient) { +pub async fn update_cost_params(args: Args, client: SigningClient, mix_id: MixId) { let denom = client.current_chain_details().mix_denom.base.as_str(); + fn convert_to_percent(value: u64) -> Percent { + Percent::from_percentage_value(value) + .expect("Invalid value") + } + + let default_profit_margin: Percent = convert_to_percent(20); + + let profit_margin_percent = match client.get_mixnode_rewarding_details(mix_id).await { + Ok(details) => details.rewarding_details + .map(|rd| rd.cost_params.profit_margin_percent) + .unwrap_or(default_profit_margin), + Err(_) => { + eprintln!("Failed to obtain profit margin from node, using default value of 20%"); + default_profit_margin + } + }; + + let profit_margin_value = args.profit_margin_percent + .map(|pm| convert_to_percent(pm as u64)) + .unwrap_or(profit_margin_percent); + + let cost_params = MixNodeCostParams { - profit_margin_percent: Percent::from_percentage_value( - args.profit_margin_percent.unwrap_or(10) as u64, - ) - .unwrap(), + profit_margin_percent: profit_margin_value, interval_operating_cost: CosmWasmCoin { denom: denom.into(), amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)), diff --git a/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs b/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs index a5d5c02883..8628e90c9e 100644 --- a/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs +++ b/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs @@ -14,7 +14,7 @@ pub(crate) async fn execute( nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_config::update_config(args, create_signing_client(global_args, network_details)?).await } nym_cli_commands::validator::mixnet::operators::mixnode::settings::MixnetOperatorsMixnodeSettingsCommands::UpdateCostParameters(args) => { - nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_cost_params::update_cost_params(args, create_signing_client(global_args, network_details)?).await + nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_cost_params::update_cost_params(args, create_signing_client(global_args, network_details), mix_id?).await } _ => unreachable!(), } From 9a43d1079a33eb5c789df21d6774621ebdf87f7c Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 27 Aug 2024 15:15:45 +0200 Subject: [PATCH 13/41] cargo fmt --- .../mixnode/settings/update_cost_params.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs index 2b64dbfdf4..06cc022d52 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs @@ -28,14 +28,14 @@ pub async fn update_cost_params(args: Args, client: SigningClient, mix_id: MixId let denom = client.current_chain_details().mix_denom.base.as_str(); fn convert_to_percent(value: u64) -> Percent { - Percent::from_percentage_value(value) - .expect("Invalid value") + Percent::from_percentage_value(value).expect("Invalid value") } let default_profit_margin: Percent = convert_to_percent(20); - + let profit_margin_percent = match client.get_mixnode_rewarding_details(mix_id).await { - Ok(details) => details.rewarding_details + Ok(details) => details + .rewarding_details .map(|rd| rd.cost_params.profit_margin_percent) .unwrap_or(default_profit_margin), Err(_) => { @@ -43,12 +43,12 @@ pub async fn update_cost_params(args: Args, client: SigningClient, mix_id: MixId default_profit_margin } }; - - let profit_margin_value = args.profit_margin_percent + + let profit_margin_value = args + .profit_margin_percent .map(|pm| convert_to_percent(pm as u64)) .unwrap_or(profit_margin_percent); - - + let cost_params = MixNodeCostParams { profit_margin_percent: profit_margin_value, interval_operating_cost: CosmWasmCoin { From 4635db73f184bed13e00e76d24ffebdeb6acb6a7 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 27 Aug 2024 16:20:44 +0200 Subject: [PATCH 14/41] update code and fmt again --- .../mixnode/settings/update_cost_params.rs | 34 ++++++++++++++----- .../mixnet/operators/mixnodes/settings/mod.rs | 2 +- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs index 06cc022d52..e76bd0bdf3 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs @@ -24,7 +24,7 @@ pub struct Args { pub interval_operating_cost: Option, } -pub async fn update_cost_params(args: Args, client: SigningClient, mix_id: MixId) { +pub async fn update_cost_params(args: Args, client: SigningClient) { let denom = client.current_chain_details().mix_denom.base.as_str(); fn convert_to_percent(value: u64) -> Percent { @@ -33,17 +33,35 @@ pub async fn update_cost_params(args: Args, client: SigningClient, mix_id: MixId let default_profit_margin: Percent = convert_to_percent(20); - let profit_margin_percent = match client.get_mixnode_rewarding_details(mix_id).await { - Ok(details) => details - .rewarding_details - .map(|rd| rd.cost_params.profit_margin_percent) - .unwrap_or(default_profit_margin), + let mixownership_response = match client.get_owned_mixnode(&client.address()).await { + Ok(response) => response, Err(_) => { - eprintln!("Failed to obtain profit margin from node, using default value of 20%"); - default_profit_margin + eprintln!("Failed to obtain mixnode details"); + return; } }; + let mix_id = match mixownership_response.mixnode_details { + Some(details) => details.bond_information.mix_id, + None => { + eprintln!("No mixnode details found"); + return; + } + }; + + let rewarding_response = match client.get_mixnode_rewarding_details(mix_id).await { + Ok(details) => details, + Err(_) => { + eprintln!("Failed to obtain rewarding details"); + return; + } + }; + + let profit_margin_percent = rewarding_response + .rewarding_details + .map(|rd| rd.cost_params.profit_margin_percent) + .unwrap_or(default_profit_margin); + let profit_margin_value = args .profit_margin_percent .map(|pm| convert_to_percent(pm as u64)) diff --git a/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs b/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs index 8628e90c9e..a5d5c02883 100644 --- a/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs +++ b/tools/nym-cli/src/validator/mixnet/operators/mixnodes/settings/mod.rs @@ -14,7 +14,7 @@ pub(crate) async fn execute( nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_config::update_config(args, create_signing_client(global_args, network_details)?).await } nym_cli_commands::validator::mixnet::operators::mixnode::settings::MixnetOperatorsMixnodeSettingsCommands::UpdateCostParameters(args) => { - nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_cost_params::update_cost_params(args, create_signing_client(global_args, network_details), mix_id?).await + nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_cost_params::update_cost_params(args, create_signing_client(global_args, network_details)?).await } _ => unreachable!(), } From eafbed6c9f195049187e85e1d839f06097e4dc3d Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 28 Aug 2024 11:21:11 +0200 Subject: [PATCH 15/41] wording --- .../mixnet/operators/mixnode/settings/update_cost_params.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs index e76bd0bdf3..bc84cf6140 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs @@ -36,7 +36,7 @@ pub async fn update_cost_params(args: Args, client: SigningClient) { let mixownership_response = match client.get_owned_mixnode(&client.address()).await { Ok(response) => response, Err(_) => { - eprintln!("Failed to obtain mixnode details"); + eprintln!("Failed to obtain owned mixnode"); return; } }; @@ -44,7 +44,7 @@ pub async fn update_cost_params(args: Args, client: SigningClient) { let mix_id = match mixownership_response.mixnode_details { Some(details) => details.bond_information.mix_id, None => { - eprintln!("No mixnode details found"); + eprintln!("Failed to obtain mixnode details"); return; } }; From ec0e1b67a0aa909f516e32302e2e3ef421513ccd Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 28 Aug 2024 11:28:17 +0200 Subject: [PATCH 16/41] adding ecash contract address --- common/network-defaults/src/mainnet.rs | 4 ++-- envs/mainnet.env | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/network-defaults/src/mainnet.rs b/common/network-defaults/src/mainnet.rs index b6723c1a4a..ffbbe8d265 100644 --- a/common/network-defaults/src/mainnet.rs +++ b/common/network-defaults/src/mainnet.rs @@ -17,8 +17,8 @@ pub const MIXNET_CONTRACT_ADDRESS: &str = "n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr"; pub const VESTING_CONTRACT_ADDRESS: &str = "n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw"; - -pub const ECASH_CONTRACT_ADDRESS: &str = ""; +pub const ECASH_CONTRACT_ADDRESS: &str = +"n1r7s6aksyc6pqardx88k3rkgfagwvj4z4zum9mmz2sfk3zm2mha0sd4dnun"; pub const GROUP_CONTRACT_ADDRESS: &str = "n1e2zq4886zzewpvpucmlw8v9p7zv692f6yck4zjzxh699dkcmlrfqk2knsr"; pub const MULTISIG_CONTRACT_ADDRESS: &str = diff --git a/envs/mainnet.env b/envs/mainnet.env index 17f546028c..e40e54a471 100644 --- a/envs/mainnet.env +++ b/envs/mainnet.env @@ -15,6 +15,7 @@ DENOMS_EXPONENT=6 MIXNET_CONTRACT_ADDRESS=n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw GROUP_CONTRACT_ADDRESS=n1e2zq4886zzewpvpucmlw8v9p7zv692f6yck4zjzxh699dkcmlrfqk2knsr +ECASH_CONTRACT_ADDRESS=n1r7s6aksyc6pqardx88k3rkgfagwvj4z4zum9mmz2sfk3zm2mha0sd4dnun MULTISIG_CONTRACT_ADDRESS=n1txayqfz5g9qww3rlflpg025xd26m9payz96u54x4fe3s2ktz39xqk67gzx COCONUT_DKG_CONTRACT_ADDRESS=n19604yflqggs9mk2z26mqygq43q2kr3n932egxx630svywd5mpxjsztfpvx From a5289cd431f9ee03c0e0eee3de918d0f10abf835 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 28 Aug 2024 11:39:49 +0200 Subject: [PATCH 17/41] update test env with ecash too --- envs/canary.env | 5 +++-- explorer-api/.env.dev | 9 ++++----- nym-wallet/nym-wallet-types/src/network/qa.rs | 12 ++++++------ nym-wallet/nym-wallet-types/src/network/sandbox.rs | 12 ++++++------ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/envs/canary.env b/envs/canary.env index 1c38b89a1a..c4aac15082 100644 --- a/envs/canary.env +++ b/envs/canary.env @@ -2,7 +2,7 @@ CONFIGURED=true RUST_LOG=info RUST_BACKTRACE=1 -NETWORK_NAME=sandbox +NETWORK_NAME=canary BECH32_PREFIX=n MIX_DENOM=unym MIX_DENOM_DISPLAY=nym @@ -12,7 +12,8 @@ DENOMS_EXPONENT=6 REWARDING_VALIDATOR_ADDRESS=n1duuyj2th2y0z4u4f4wtljpdz9s3pxtu0xx6zdz MIXNET_CONTRACT_ADDRESS=n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g -COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n1mf6ptkssddfmxvhdx0ech0k03ktp6kf9yk59renau2gvht3nq2gqt5tdrk +VESTING_CONTRACT_ADDRESS=n1780emnrt7v9uqx5txhpxc0z8zfawq0czjmtd4q2maz83cckwjlfsx45u6c +ECASH_CONTRACT_ADDRESS=n14jf8r2kxlymgjkp3xj8xuyud7h974648qdn9tsgsj0pascmntt9s3lvlwm GROUP_CONTRACT_ADDRESS=n1qg5ega6dykkxc307y25pecuufrjkxkaggkkxh7nad0vhyhtuhw3sa07c47 MULTISIG_CONTRACT_ADDRESS=n1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqx5a364 COCONUT_DKG_CONTRACT_ADDRESS=n1aakfpghcanxtc45gpqlx8j3rq0zcpyf49qmhm9mdjrfx036h4z5sy2vfh9 diff --git a/explorer-api/.env.dev b/explorer-api/.env.dev index 61113ab13d..f332cff85e 100644 --- a/explorer-api/.env.dev +++ b/explorer-api/.env.dev @@ -13,11 +13,10 @@ DENOMS_EXPONENT=6 REWARDING_VALIDATOR_ADDRESS=n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa MIXNET_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav VESTING_CONTRACT_ADDRESS=n1unyuj8qnmygvzuex3dwmg9yzt9alhvyeat0uu0jedg2wj33efl5qackslz -BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0 -COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n16a32stm6kknhq5cc8rx77elr66pygf2hfszw7wvpq746x3uffylqkjar4l -GROUP_CONTRACT_ADDRESS=n1pd7kfgvr5tpcv0xnlv46c4jsq9jg2r799xxrcwqdm4l2jhq2pjwqrmz5ju -MULTISIG_CONTRACT_ADDRESS=n14ph4e660eyqz0j36zlkaey4zgzexm5twkmjlqaequxr2cjm9eprqsmad6k -COCONUT_DKG_CONTRACT_ADDRESS=n1ahg0erc2fs6xx3j5m8sfx3ryuzdjh6kf6qm9plsf865fltekyrfsesac6a +ECASH_CONTRACT_ADDRESS=n1v3vydvs2ued84yv3khqwtgldmgwn0elljsdh08dr5s2j9x4rc5fs9jlwz9 +GROUP_CONTRACT_ADDRESS=n1ewmwz97xm0h8rdk8sw7h9mwn866qkx9hl9zlmagqfkhuzvwk5hhq844ue9 +MULTISIG_CONTRACT_ADDRESS=n1tz0setr8vkh9udp8xyxgpqc89ns27k4d0jx2h942hr0ax63yjhmqz6xct8 +COCONUT_DKG_CONTRACT_ADDRESS=n1v3n2ly2dp3a9ng3ff6rh26yfkn0pc5hed7w2shc5u9ca5c865utqj5elvh STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0" diff --git a/nym-wallet/nym-wallet-types/src/network/qa.rs b/nym-wallet/nym-wallet-types/src/network/qa.rs index 00e9f1160f..761d08f614 100644 --- a/nym-wallet/nym-wallet-types/src/network/qa.rs +++ b/nym-wallet/nym-wallet-types/src/network/qa.rs @@ -15,14 +15,14 @@ pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "n1hm4y6fzgxgu688jgf7ek66px6xkrtmn3gyk8fax3eawhp68c2d5qujz296"; pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "n1jlzdxnyces4hrhqz68dqk28mrw5jgwtcfq0c2funcwrmw0dx9l9s8nnnvj"; -pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = - "n1w798gp0zqv3s9hjl3jlnwxtwhykga6rn93p46q2crsdqhaj3y4gs68f74j"; +pub(crate) const ECASH_CONTRACT_ADDRESS: &str = + "n13xspq62y9gq6nueqmywxcdv2yep4p6nzv98w2889k25v3nhdy2dq2rkrk7"; pub(crate) const GROUP_CONTRACT_ADDRESS: &str = - "n1sthrn5ep8ls5vzz8f9gp89khhmedahhdqd244dh9uqzk3hx2pzrsvf7zgk"; + "n13l7rwuwktklrwskc7m6lv70zws07en85uma28j7dxwsz9y5hvvhspl7a2t"; pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = - "n1sr06m8yqg0wzqqyqvzvp5t07dj4nevx9u8qc7j4qa72qu8e3ct8qledthy"; + "n138c9pyf7f3hyx0j3t6vmsz7ultnw2wj0lu6hzndep9z5grgq9haqlc25k0"; pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str = - "n1udfs22xpxle475m2nz7u47jfa3vngncdegmczwwdx00cmetypa3s7uyuqn"; + "n1pk8jgr6y4c5k93gz7qf3xc0hvygmp7csk88c2tf8l39tkq6834wq2a6dtr"; // -- Constructor functions -- @@ -48,7 +48,7 @@ pub(crate) fn network_details() -> nym_network_defaults::NymNetworkDetails { contracts: NymContracts { mixnet_contract_address: parse_optional_str(MIXNET_CONTRACT_ADDRESS), vesting_contract_address: parse_optional_str(VESTING_CONTRACT_ADDRESS), - ecash_contract_address: parse_optional_str(COCONUT_BANDWIDTH_CONTRACT_ADDRESS), + ecash_contract_address: parse_optional_str(ECASH_CONTRACT_ADDRESS), group_contract_address: parse_optional_str(GROUP_CONTRACT_ADDRESS), multisig_contract_address: parse_optional_str(MULTISIG_CONTRACT_ADDRESS), coconut_dkg_contract_address: parse_optional_str(COCONUT_DKG_CONTRACT_ADDRESS), diff --git a/nym-wallet/nym-wallet-types/src/network/sandbox.rs b/nym-wallet/nym-wallet-types/src/network/sandbox.rs index b545dd134b..c436c9f09e 100644 --- a/nym-wallet/nym-wallet-types/src/network/sandbox.rs +++ b/nym-wallet/nym-wallet-types/src/network/sandbox.rs @@ -15,14 +15,14 @@ pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav"; pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "n1unyuj8qnmygvzuex3dwmg9yzt9alhvyeat0uu0jedg2wj33efl5qackslz"; -pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = - "n16a32stm6kknhq5cc8rx77elr66pygf2hfszw7wvpq746x3uffylqkjar4l"; +pub(crate) const ECASH_CONTRACT_ADDRESS: &str = + "n1v3vydvs2ued84yv3khqwtgldmgwn0elljsdh08dr5s2j9x4rc5fs9jlwz9"; pub(crate) const GROUP_CONTRACT_ADDRESS: &str = - "n1pd7kfgvr5tpcv0xnlv46c4jsq9jg2r799xxrcwqdm4l2jhq2pjwqrmz5ju"; + "n1ewmwz97xm0h8rdk8sw7h9mwn866qkx9hl9zlmagqfkhuzvwk5hhq844ue9"; pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = - "n14ph4e660eyqz0j36zlkaey4zgzexm5twkmjlqaequxr2cjm9eprqsmad6k"; + "n1tz0setr8vkh9udp8xyxgpqc89ns27k4d0jx2h942hr0ax63yjhmqz6xct8"; pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str = - "n1ahg0erc2fs6xx3j5m8sfx3ryuzdjh6kf6qm9plsf865fltekyrfsesac6a"; + "n1v3n2ly2dp3a9ng3ff6rh26yfkn0pc5hed7w2shc5u9ca5c865utqj5elvh"; // -- Constructor functions -- @@ -48,7 +48,7 @@ pub(crate) fn network_details() -> nym_network_defaults::NymNetworkDetails { contracts: NymContracts { mixnet_contract_address: parse_optional_str(MIXNET_CONTRACT_ADDRESS), vesting_contract_address: parse_optional_str(VESTING_CONTRACT_ADDRESS), - ecash_contract_address: parse_optional_str(COCONUT_BANDWIDTH_CONTRACT_ADDRESS), + ecash_contract_address: parse_optional_str(ECASH_CONTRACT_ADDRESS), group_contract_address: parse_optional_str(GROUP_CONTRACT_ADDRESS), multisig_contract_address: parse_optional_str(MULTISIG_CONTRACT_ADDRESS), coconut_dkg_contract_address: parse_optional_str(COCONUT_DKG_CONTRACT_ADDRESS), From 73fc2d6bb24efcdd0621bd957fd160505e875e6c Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 28 Aug 2024 11:43:16 +0200 Subject: [PATCH 18/41] remove unused import --- .../mixnet/operators/mixnode/settings/update_cost_params.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs index bc84cf6140..7c09ba2946 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/settings/update_cost_params.rs @@ -5,7 +5,7 @@ use crate::context::SigningClient; use clap::Parser; use cosmwasm_std::Uint128; use log::info; -use nym_mixnet_contract_common::{MixId, MixNodeCostParams, Percent}; +use nym_mixnet_contract_common::{MixNodeCostParams, Percent}; use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; use nym_validator_client::nyxd::CosmWasmCoin; From 7ae56b08b3abb600286a0193c8071dc94df4e6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 28 Aug 2024 15:19:55 +0100 Subject: [PATCH 19/41] using legacy signing payload in CLI and verifying both variants in contract --- .../gateway/gateway_bonding_sign_payload.rs | 4 +- .../mixnode/mixnode_bonding_sign_payload.rs | 6 ++- .../contracts-common/src/signing/mod.rs | 28 ++++++++++++++ .../mixnet-contract/src/signing_types.rs | 34 ++++++++++++++++- .../mixnet/src/gateways/signature_helpers.rs | 30 ++++++++++++--- .../mixnet/src/mixnodes/signature_helpers.rs | 37 ++++++++++++++++--- .../src-tauri/src/operations/helpers.rs | 8 ++-- 7 files changed, 128 insertions(+), 19 deletions(-) diff --git a/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs b/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs index ba19f61867..0747dcac3c 100644 --- a/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs +++ b/common/commands/src/validator/mixnet/operators/gateway/gateway_bonding_sign_payload.rs @@ -6,7 +6,7 @@ use crate::utils::{account_id_to_cw_addr, DataWrapper}; use clap::Parser; use cosmwasm_std::Coin; use nym_bin_common::output_format::OutputFormat; -use nym_mixnet_contract_common::construct_gateway_bonding_sign_payload; +use nym_mixnet_contract_common::construct_legacy_gateway_bonding_sign_payload; use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT}; use nym_validator_client::nyxd::contract_traits::MixnetQueryClient; @@ -71,7 +71,7 @@ pub async fn create_payload(args: Args, client: SigningClient) { let address = account_id_to_cw_addr(&client.address()); - let payload = construct_gateway_bonding_sign_payload(nonce, address, coin, gateway); + let payload = construct_legacy_gateway_bonding_sign_payload(nonce, address, coin, gateway); let wrapper = DataWrapper::new(payload.to_base58_string().unwrap()); println!("{}", args.output.format(&wrapper)) } diff --git a/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs b/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs index a492b3a0b6..3eda67a2e9 100644 --- a/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs +++ b/common/commands/src/validator/mixnet/operators/mixnode/mixnode_bonding_sign_payload.rs @@ -7,7 +7,9 @@ use clap::Parser; use cosmwasm_std::{Coin, Uint128}; use nym_bin_common::output_format::OutputFormat; use nym_contracts_common::Percent; -use nym_mixnet_contract_common::{construct_mixnode_bonding_sign_payload, MixNodeCostParams}; +use nym_mixnet_contract_common::{ + construct_legacy_mixnode_bonding_sign_payload, MixNodeCostParams, +}; use nym_network_defaults::{ DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT, }; @@ -98,7 +100,7 @@ pub async fn create_payload(args: Args, client: SigningClient) { let address = account_id_to_cw_addr(&client.address()); let payload = - construct_mixnode_bonding_sign_payload(nonce, address, coin, mixnode, cost_params); + construct_legacy_mixnode_bonding_sign_payload(nonce, address, coin, mixnode, cost_params); let wrapper = DataWrapper::new(payload.to_base58_string().unwrap()); println!("{}", args.output.format(&wrapper)) } diff --git a/common/cosmwasm-smart-contracts/contracts-common/src/signing/mod.rs b/common/cosmwasm-smart-contracts/contracts-common/src/signing/mod.rs index d2722b2f59..228e188b84 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/src/signing/mod.rs +++ b/common/cosmwasm-smart-contracts/contracts-common/src/signing/mod.rs @@ -248,3 +248,31 @@ impl ContractMessageContent { } } } + +impl From> for LegacyContractMessageContent { + fn from(value: ContractMessageContent) -> Self { + LegacyContractMessageContent { + sender: value.sender, + proxy: None, + funds: value.funds, + data: value.data, + } + } +} + +#[derive(Serialize)] +pub struct LegacyContractMessageContent { + pub sender: Addr, + pub proxy: Option, + pub funds: Vec, + pub data: T, +} + +impl SigningPurpose for LegacyContractMessageContent +where + T: SigningPurpose, +{ + fn message_type() -> MessageType { + T::message_type() + } +} diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/signing_types.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/signing_types.rs index 84c9b8b4aa..261fa99ff0 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/signing_types.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/signing_types.rs @@ -4,13 +4,18 @@ use crate::families::FamilyHead; use crate::{Gateway, IdentityKey, MixNode, MixNodeCostParams}; use contracts_common::signing::{ - ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose, + ContractMessageContent, LegacyContractMessageContent, MessageType, Nonce, SignableMessage, + SigningPurpose, }; use cosmwasm_std::{Addr, Coin}; use serde::Serialize; pub type SignableMixNodeBondingMsg = SignableMessage>; pub type SignableGatewayBondingMsg = SignableMessage>; +pub type SignableLegacyMixNodeBondingMsg = + SignableMessage>; +pub type SignableLegacyGatewayBondingMsg = + SignableMessage>; pub type SignableFamilyJoinPermitMsg = SignableMessage; #[derive(Serialize)] @@ -47,6 +52,20 @@ pub fn construct_mixnode_bonding_sign_payload( SignableMessage::new(nonce, content) } +pub fn construct_legacy_mixnode_bonding_sign_payload( + nonce: Nonce, + sender: Addr, + pledge: Coin, + mix_node: MixNode, + cost_params: MixNodeCostParams, +) -> SignableLegacyMixNodeBondingMsg { + let payload = MixnodeBondingPayload::new(mix_node, cost_params); + let content: LegacyContractMessageContent<_> = + ContractMessageContent::new(sender, vec![pledge], payload).into(); + + SignableMessage::new(nonce, content) +} + #[derive(Serialize)] pub struct GatewayBondingPayload { gateway: Gateway, @@ -76,6 +95,19 @@ pub fn construct_gateway_bonding_sign_payload( SignableMessage::new(nonce, content) } +pub fn construct_legacy_gateway_bonding_sign_payload( + nonce: Nonce, + sender: Addr, + pledge: Coin, + gateway: Gateway, +) -> SignableLegacyGatewayBondingMsg { + let payload = GatewayBondingPayload::new(gateway); + let content: LegacyContractMessageContent<_> = + ContractMessageContent::new(sender, vec![pledge], payload).into(); + + SignableMessage::new(nonce, content) +} + #[derive(Serialize)] pub struct FamilyJoinPermit { // the granter of this permit diff --git a/contracts/mixnet/src/gateways/signature_helpers.rs b/contracts/mixnet/src/gateways/signature_helpers.rs index 46d37c6073..6f9b712554 100644 --- a/contracts/mixnet/src/gateways/signature_helpers.rs +++ b/contracts/mixnet/src/gateways/signature_helpers.rs @@ -5,7 +5,9 @@ use crate::signing::storage as signing_storage; use crate::support::helpers::decode_ed25519_identity_key; use cosmwasm_std::{Addr, Coin, Deps}; use mixnet_contract_common::error::MixnetContractError; -use mixnet_contract_common::{construct_gateway_bonding_sign_payload, Gateway}; +use mixnet_contract_common::{ + construct_gateway_bonding_sign_payload, construct_legacy_gateway_bonding_sign_payload, Gateway, +}; use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::signing::Verifier; @@ -19,13 +21,31 @@ pub(crate) fn verify_gateway_bonding_signature( // recover the public key let public_key = decode_ed25519_identity_key(&gateway.identity_key)?; - // reconstruct the payload + // reconstruct the payload, first try the current format, then attempt legacy let nonce = signing_storage::get_signing_nonce(deps.storage, sender.clone())?; - let msg = construct_gateway_bonding_sign_payload(nonce, sender, pledge, gateway); + let msg = construct_gateway_bonding_sign_payload( + nonce, + sender.clone(), + pledge.clone(), + gateway.clone(), + ); - if deps.api.verify_message(msg, signature, &public_key)? { + if deps + .api + .verify_message(msg, signature.clone(), &public_key)? + { Ok(()) } else { - Err(MixnetContractError::InvalidEd25519Signature) + // attempt to use legacy + let msg_legacy = + construct_legacy_gateway_bonding_sign_payload(nonce, sender, pledge, gateway); + if deps + .api + .verify_message(msg_legacy, signature, &public_key)? + { + Ok(()) + } else { + Err(MixnetContractError::InvalidEd25519Signature) + } } } diff --git a/contracts/mixnet/src/mixnodes/signature_helpers.rs b/contracts/mixnet/src/mixnodes/signature_helpers.rs index 975bb55669..04942aaff5 100644 --- a/contracts/mixnet/src/mixnodes/signature_helpers.rs +++ b/contracts/mixnet/src/mixnodes/signature_helpers.rs @@ -5,7 +5,10 @@ use crate::signing::storage as signing_storage; use crate::support::helpers::decode_ed25519_identity_key; use cosmwasm_std::{Addr, Coin, Deps}; use mixnet_contract_common::error::MixnetContractError; -use mixnet_contract_common::{construct_mixnode_bonding_sign_payload, MixNode, MixNodeCostParams}; +use mixnet_contract_common::{ + construct_legacy_mixnode_bonding_sign_payload, construct_mixnode_bonding_sign_payload, MixNode, + MixNodeCostParams, +}; use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::signing::Verifier; @@ -20,13 +23,37 @@ pub(crate) fn verify_mixnode_bonding_signature( // recover the public key let public_key = decode_ed25519_identity_key(&mixnode.identity_key)?; - // reconstruct the payload + // reconstruct the payload, first try the current format, then attempt legacy let nonce = signing_storage::get_signing_nonce(deps.storage, sender.clone())?; - let msg = construct_mixnode_bonding_sign_payload(nonce, sender, pledge, mixnode, cost_params); + let msg = construct_mixnode_bonding_sign_payload( + nonce, + sender.clone(), + pledge.clone(), + mixnode.clone(), + cost_params.clone(), + ); - if deps.api.verify_message(msg, signature, &public_key)? { + if deps + .api + .verify_message(msg, signature.clone(), &public_key)? + { Ok(()) } else { - Err(MixnetContractError::InvalidEd25519Signature) + // attempt to use legacy + let msg_legacy = construct_legacy_mixnode_bonding_sign_payload( + nonce, + sender, + pledge, + mixnode, + cost_params, + ); + if deps + .api + .verify_message(msg_legacy, signature, &public_key)? + { + Ok(()) + } else { + Err(MixnetContractError::InvalidEd25519Signature) + } } } diff --git a/nym-wallet/src-tauri/src/operations/helpers.rs b/nym-wallet/src-tauri/src/operations/helpers.rs index 2b5631eb58..da0093e293 100644 --- a/nym-wallet/src-tauri/src/operations/helpers.rs +++ b/nym-wallet/src-tauri/src/operations/helpers.rs @@ -9,8 +9,8 @@ use nym_contracts_common::signing::{ }; use nym_crypto::asymmetric::identity; use nym_mixnet_contract_common::{ - construct_mixnode_bonding_sign_payload, Gateway, GatewayBondingPayload, MixNode, - MixNodeCostParams, SignableGatewayBondingMsg, SignableMixNodeBondingMsg, + construct_legacy_mixnode_bonding_sign_payload, Gateway, GatewayBondingPayload, MixNode, + MixNodeCostParams, SignableGatewayBondingMsg, SignableLegacyMixNodeBondingMsg, }; use nym_validator_client::nyxd::contract_traits::MixnetQueryClient; use nym_validator_client::nyxd::error::NyxdError; @@ -42,14 +42,14 @@ pub(crate) async fn create_mixnode_bonding_sign_payload Result { +) -> Result { if vesting { return Err(BackendError::UnsupportedVestingOperation); } let sender = client.cw_address(); let nonce = client.get_signing_nonce().await?; - Ok(construct_mixnode_bonding_sign_payload( + Ok(construct_legacy_mixnode_bonding_sign_payload( nonce, sender, pledge.into(), From c17f0ac3f87eeb502c17327277bb363bfe996605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 28 Aug 2024 16:30:30 +0100 Subject: [PATCH 20/41] added explicit updateable admin to the mixnet contract --- Cargo.lock | 1 + .../contract_traits/mixnet_query_client.rs | 5 +++ .../contract_traits/mixnet_signing_client.rs | 11 ++++++ .../mixnet-contract/Cargo.toml | 1 + .../mixnet-contract/src/error.rs | 4 +++ .../mixnet-contract/src/msg.rs | 9 +++++ .../mixnet-contract/src/types.rs | 3 -- contracts/Cargo.lock | 2 ++ contracts/mixnet/Cargo.toml | 1 + contracts/mixnet/src/constants.rs | 1 + contracts/mixnet/src/contract.rs | 17 ++++++---- contracts/mixnet/src/interval/transactions.rs | 10 +++--- .../src/mixnet_contract_settings/queries.rs | 7 +++- .../src/mixnet_contract_settings/storage.rs | 12 ++++--- .../mixnet_contract_settings/transactions.rs | 25 +++++++++----- contracts/mixnet/src/queued_migrations.rs | 34 +++++++++++++++++-- contracts/mixnet/src/rewards/transactions.rs | 18 +++++----- contracts/mixnet/src/support/helpers.rs | 14 -------- contracts/mixnet/src/support/tests/mod.rs | 7 ++-- nym-wallet/Cargo.lock | 1 + 20 files changed, 129 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad525671a6..fafe3bdb0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5272,6 +5272,7 @@ dependencies = [ "bs58 0.4.0", "cosmwasm-schema", "cosmwasm-std", + "cw-controllers", "cw2", "humantime-serde", "log", diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs index 95d692d592..47b67d8f16 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs @@ -42,6 +42,10 @@ pub trait MixnetQueryClient { // state/sys-params-related + async fn admin(&self) -> Result { + self.query_mixnet_contract(MixnetQueryMsg::Admin {}).await + } + async fn get_mixnet_contract_version(&self) -> Result { self.query_mixnet_contract(MixnetQueryMsg::GetContractVersion {}) .await @@ -580,6 +584,7 @@ mod tests { msg: MixnetQueryMsg, ) -> u32 { match msg { + MixnetQueryMsg::Admin {} => client.admin().ignore(), MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after } => client .get_all_family_members_paged(start_after, limit) .ignore(), diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs index 26a766a190..00b0755477 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs @@ -31,6 +31,15 @@ pub trait MixnetSigningClient { // state/sys-params-related + async fn update_admin( + &self, + admin: String, + fee: Option, + ) -> Result { + self.execute_mixnet_contract(fee, MixnetExecuteMsg::UpdateAdmin { admin }, vec![]) + .await + } + async fn update_rewarding_validator_address( &self, address: AccountId, @@ -752,6 +761,7 @@ where mod tests { use super::*; use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue}; + use nym_mixnet_contract_common::ExecuteMsg; // it's enough that this compiles and clippy is happy about it #[allow(dead_code)] @@ -760,6 +770,7 @@ mod tests { msg: MixnetExecuteMsg, ) { match msg { + ExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(), MixnetExecuteMsg::AssignNodeLayer { mix_id, layer } => { client.assign_node_layer(mix_id, layer, None).ignore() } diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml b/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml index 31e422a49c..8968f1c8d6 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml @@ -12,6 +12,7 @@ repository = { workspace = true } bs58 = "0.4.0" cosmwasm-std = { workspace = true } cosmwasm-schema = { workspace = true } +cw-controllers = { workspace = true } cw2 = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } serde_repr = { workspace = true } diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs index 710ca20b16..12f2030acc 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs @@ -5,6 +5,7 @@ use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, Pr use contracts_common::signing::verifier::ApiVerifierError; use contracts_common::Percent; use cosmwasm_std::{Addr, Coin, Decimal, Uint128}; +use cw_controllers::AdminError; use thiserror::Error; #[derive(Error, Debug, PartialEq)] @@ -12,6 +13,9 @@ pub enum MixnetContractError { #[error("could not perform contract migration: {comment}")] FailedMigration { comment: String }, + #[error(transparent)] + Admin(#[from] AdminError), + #[error("{source}")] StdErr { #[from] diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs index 90110e0dc6..863fdc0327 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs @@ -110,6 +110,11 @@ impl InitialRewardingParams { #[cw_serde] pub enum ExecuteMsg { + /// Change the admin + UpdateAdmin { + admin: String, + }, + AssignNodeLayer { mix_id: MixId, layer: Layer, @@ -292,6 +297,7 @@ pub enum ExecuteMsg { impl ExecuteMsg { pub fn default_memo(&self) -> String { match self { + ExecuteMsg::UpdateAdmin { admin } => format!("updating contract admin to {admin}"), ExecuteMsg::AssignNodeLayer { mix_id, layer } => { format!("assigning mix {mix_id} for layer {layer:?}") } @@ -408,6 +414,9 @@ impl ExecuteMsg { #[cw_serde] #[cfg_attr(feature = "schema", derive(QueryResponses))] pub enum QueryMsg { + #[cfg_attr(feature = "schema", returns(cw_controllers::AdminResponse))] + Admin {}, + // families /// Gets the list of families registered in this contract. #[cfg_attr(feature = "schema", returns(PagedFamiliesResponse))] diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs index 18c7fc6606..e513a392c1 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs @@ -186,9 +186,6 @@ impl Index for LayerDistribution { /// The current state of the mixnet contract. #[cw_serde] pub struct ContractState { - /// Address of the contract owner. - pub owner: Addr, - /// Address of "rewarding validator" (nym-api) that's allowed to send any rewarding-related transactions. pub rewarding_validator_address: Addr, diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 3bdbdb9022..f2e9d29ad2 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1276,6 +1276,7 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", + "cw-controllers", "cw-storage-plus", "cw2", "nym-contracts-common", @@ -1295,6 +1296,7 @@ dependencies = [ "bs58 0.4.0", "cosmwasm-schema", "cosmwasm-std", + "cw-controllers", "cw2", "humantime-serde", "log", diff --git a/contracts/mixnet/Cargo.toml b/contracts/mixnet/Cargo.toml index 94133686d5..957f981f2e 100644 --- a/contracts/mixnet/Cargo.toml +++ b/contracts/mixnet/Cargo.toml @@ -34,6 +34,7 @@ cosmwasm-schema = { workspace = true, optional = true } cosmwasm-std = { workspace = true } cosmwasm-storage = { workspace = true } cosmwasm-derive = { workspace = true } +cw-controllers = { workspace = true } cw2 = { workspace = true } cw-storage-plus = { workspace = true } diff --git a/contracts/mixnet/src/constants.rs b/contracts/mixnet/src/constants.rs index 17a62a25a8..0ea867c00c 100644 --- a/contracts/mixnet/src/constants.rs +++ b/contracts/mixnet/src/constants.rs @@ -57,6 +57,7 @@ pub const PENDING_INTERVAL_EVENTS_NAMESPACE: &str = "pie"; pub const LAST_EPOCH_EVENT_ID_KEY: &str = "lee"; pub const LAST_INTERVAL_EVENT_ID_KEY: &str = "lie"; +pub const ADMIN_STORAGE_KEY: &str = "admin"; pub const CONTRACT_STATE_KEY: &str = "state"; pub const LAYER_DISTRIBUTION_KEY: &str = "layers"; diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 884565d142..b9fe131e6d 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -21,7 +21,6 @@ const CONTRACT_NAME: &str = "crate:nym-mixnet-contract"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); fn default_initial_state( - owner: Addr, rewarding_validator_address: Addr, rewarding_denom: String, vesting_contract_address: Addr, @@ -29,7 +28,6 @@ fn default_initial_state( interval_operating_cost: OperatingCostRange, ) -> ContractState { ContractState { - owner, rewarding_validator_address, vesting_contract_address, rewarding_denom: rewarding_denom.clone(), @@ -56,7 +54,7 @@ fn default_initial_state( /// `msg` is the contract initialization message, sort of like a constructor call. #[entry_point] pub fn instantiate( - deps: DepsMut<'_>, + mut deps: DepsMut<'_>, env: Env, info: MessageInfo, msg: InstantiateMsg, @@ -72,7 +70,6 @@ pub fn instantiate( let rewarding_validator_address = deps.api.addr_validate(&msg.rewarding_validator_address)?; let vesting_contract_address = deps.api.addr_validate(&msg.vesting_contract_address)?; let state = default_initial_state( - info.sender, rewarding_validator_address.clone(), msg.rewarding_denom, vesting_contract_address, @@ -90,7 +87,7 @@ pub fn instantiate( starting_interval, rewarding_validator_address, )?; - mixnet_params_storage::initialise_storage(deps.storage, state)?; + mixnet_params_storage::initialise_storage(deps.branch(), state, info.sender)?; mixnode_storage::initialise_storage(deps.storage)?; rewards_storage::initialise_storage(deps.storage, reward_params)?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; @@ -108,6 +105,11 @@ pub fn execute( msg: ExecuteMsg, ) -> Result { match msg { + ExecuteMsg::UpdateAdmin { admin } => { + crate::mixnet_contract_settings::transactions::try_update_contract_admin( + deps, info, admin, + ) + } ExecuteMsg::AssignNodeLayer { mix_id, layer } => { crate::mixnodes::transactions::assign_mixnode_layer(deps, info, mix_id, layer) } @@ -335,6 +337,9 @@ pub fn query( QueryMsg::GetState {} => { to_binary(&crate::mixnet_contract_settings::queries::query_contract_state(deps)?) } + QueryMsg::Admin {} => to_binary(&crate::mixnet_contract_settings::queries::query_admin( + deps, + )?), QueryMsg::GetRewardingParams {} => { to_binary(&crate::rewards::queries::query_rewarding_params(deps)?) } @@ -536,6 +541,7 @@ pub fn migrate( cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; crate::queued_migrations::vesting_purge(deps.branch())?; + crate::queued_migrations::explicit_contract_admin(deps.branch())?; // due to circular dependency on contract addresses (i.e. mixnet contract requiring vesting contract address // and vesting contract requiring the mixnet contract address), if we ever want to deploy any new fresh @@ -595,7 +601,6 @@ mod tests { assert!(res.is_ok()); let expected_state = ContractState { - owner: Addr::unchecked("sender"), rewarding_validator_address: Addr::unchecked("foomp123"), vesting_contract_address: Addr::unchecked("bar456"), rewarding_denom: "uatom".into(), diff --git a/contracts/mixnet/src/interval/transactions.rs b/contracts/mixnet/src/interval/transactions.rs index 349545984f..adc8faa9cc 100644 --- a/contracts/mixnet/src/interval/transactions.rs +++ b/contracts/mixnet/src/interval/transactions.rs @@ -5,11 +5,12 @@ use super::storage; use crate::interval::helpers::change_interval_config; use crate::interval::pending_events::ContractExecutableEvent; use crate::interval::storage::push_new_interval_event; +use crate::mixnet_contract_settings::storage::ADMIN; use crate::mixnodes::transactions::update_mixnode_layer; use crate::rewards; use crate::rewards::storage as rewards_storage; use crate::support::helpers::{ - ensure_can_advance_epoch, ensure_epoch_in_progress_state, ensure_is_authorized, ensure_is_owner, + ensure_can_advance_epoch, ensure_epoch_in_progress_state, ensure_is_authorized, }; use cosmwasm_std::{DepsMut, Env, MessageInfo, Order, Response, Storage}; use mixnet_contract_common::error::MixnetContractError; @@ -325,7 +326,7 @@ pub(crate) fn try_update_interval_config( epoch_duration_secs: u64, force_immediately: bool, ) -> Result { - ensure_is_owner(info.sender, deps.storage)?; + ADMIN.assert_admin(deps.as_ref(), &info.sender)?; if epochs_in_interval == 0 { return Err(MixnetContractError::EpochsInIntervalZero); @@ -1766,6 +1767,7 @@ mod tests { use super::*; use cosmwasm_std::testing::mock_info; use cosmwasm_std::Decimal; + use cw_controllers::AdminError::NotAdmin; use std::time::Duration; #[test] @@ -1831,11 +1833,11 @@ mod tests { 1000, false, ); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let res = try_update_interval_config(test.deps_mut(), env.clone(), random, 100, 1000, false); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let res = try_update_interval_config(test.deps_mut(), env, owner, 100, 1000, false); assert!(res.is_ok()) diff --git a/contracts/mixnet/src/mixnet_contract_settings/queries.rs b/contracts/mixnet/src/mixnet_contract_settings/queries.rs index ca939d4334..cfcda13e48 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/queries.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/queries.rs @@ -2,10 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 use super::storage; +use crate::mixnet_contract_settings::storage::ADMIN; use cosmwasm_std::{Deps, StdResult}; +use cw_controllers::AdminResponse; use mixnet_contract_common::{ContractBuildInformation, ContractState, ContractStateParams}; use nym_contracts_common::get_build_information; +pub(crate) fn query_admin(deps: Deps<'_>) -> StdResult { + ADMIN.query_admin(deps) +} + pub(crate) fn query_contract_state(deps: Deps<'_>) -> StdResult { storage::CONTRACT_STATE.load(deps.storage) } @@ -37,7 +43,6 @@ pub(crate) mod tests { let mut deps = test_helpers::init_contract(); let dummy_state = ContractState { - owner: Addr::unchecked("someowner"), rewarding_validator_address: Addr::unchecked("monitor"), vesting_contract_address: Addr::unchecked("foomp"), rewarding_denom: "unym".to_string(), diff --git a/contracts/mixnet/src/mixnet_contract_settings/storage.rs b/contracts/mixnet/src/mixnet_contract_settings/storage.rs index 278b6baacf..0c8502089e 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/storage.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/storage.rs @@ -1,14 +1,16 @@ // Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::constants::CONTRACT_STATE_KEY; -use cosmwasm_std::{Addr, Storage}; +use crate::constants::{ADMIN_STORAGE_KEY, CONTRACT_STATE_KEY}; +use cosmwasm_std::{Addr, DepsMut, Storage}; use cosmwasm_std::{Coin, StdResult}; +use cw_controllers::Admin; use cw_storage_plus::Item; use mixnet_contract_common::error::MixnetContractError; use mixnet_contract_common::{ContractState, OperatingCostRange, ProfitMarginRange}; pub(crate) const CONTRACT_STATE: Item<'_, ContractState> = Item::new(CONTRACT_STATE_KEY); +pub(crate) const ADMIN: Admin = Admin::new(ADMIN_STORAGE_KEY); pub fn rewarding_validator_address(storage: &dyn Storage) -> Result { Ok(CONTRACT_STATE @@ -66,8 +68,10 @@ pub(crate) fn vesting_contract_address(storage: &dyn Storage) -> Result, initial_state: ContractState, + initial_admin: Addr, ) -> StdResult<()> { - CONTRACT_STATE.save(storage, &initial_state) + CONTRACT_STATE.save(deps.storage, &initial_state)?; + ADMIN.set(deps, Some(initial_admin)) } diff --git a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs index 19b753189e..fc6a9ce30e 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::storage; +use crate::mixnet_contract_settings::storage::ADMIN; use cosmwasm_std::DepsMut; use cosmwasm_std::MessageInfo; use cosmwasm_std::Response; @@ -11,6 +12,16 @@ use mixnet_contract_common::events::{ }; use mixnet_contract_common::ContractStateParams; +pub fn try_update_contract_admin( + deps: DepsMut<'_>, + info: MessageInfo, + new_admin: String, +) -> Result { + let new_admin = deps.api.addr_validate(&new_admin)?; + + Ok(ADMIN.execute_update_admin(deps, info, Some(new_admin))?) +} + pub fn try_update_rewarding_validator_address( deps: DepsMut<'_>, info: MessageInfo, @@ -18,9 +29,7 @@ pub fn try_update_rewarding_validator_address( ) -> Result { let mut state = storage::CONTRACT_STATE.load(deps.storage)?; - if info.sender != state.owner { - return Err(MixnetContractError::Unauthorized); - } + ADMIN.assert_admin(deps.as_ref(), &info.sender)?; let new_address = deps.api.addr_validate(&address)?; let old_address = state.rewarding_validator_address; @@ -43,10 +52,7 @@ pub(crate) fn try_update_contract_settings( ) -> Result { let mut state = storage::CONTRACT_STATE.load(deps.storage)?; - // check if this is executed by the owner, if not reject the transaction - if info.sender != state.owner { - return Err(MixnetContractError::Unauthorized); - } + ADMIN.assert_admin(deps.as_ref(), &info.sender)?; let response = Response::new().add_event(new_settings_update_event(&state.params, ¶ms)); @@ -65,6 +71,7 @@ pub mod tests { use crate::support::tests::test_helpers; use cosmwasm_std::testing::mock_info; use cosmwasm_std::{Addr, Coin, Uint128}; + use cw_controllers::AdminError::NotAdmin; #[test] fn update_contract_rewarding_validtor_address() { @@ -76,7 +83,7 @@ pub mod tests { info, "not-the-creator".to_string(), ); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let info = mock_info("creator", &[]); let res = try_update_rewarding_validator_address( @@ -136,7 +143,7 @@ pub mod tests { // cannot be updated from non-owner account let info = mock_info("not-the-creator", &[]); let res = try_update_contract_settings(deps.as_mut(), info, new_params.clone()); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); // but works fine from the creator account let info = mock_info("creator", &[]); diff --git a/contracts/mixnet/src/queued_migrations.rs b/contracts/mixnet/src/queued_migrations.rs index ab410897e9..a6979d8c5c 100644 --- a/contracts/mixnet/src/queued_migrations.rs +++ b/contracts/mixnet/src/queued_migrations.rs @@ -1,10 +1,14 @@ // Copyright 2022-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::constants::CONTRACT_STATE_KEY; use crate::interval::storage as interval_storage; -use cosmwasm_std::{DepsMut, Order, Storage}; +use crate::mixnet_contract_settings::storage as mixnet_params_storage; +use cosmwasm_std::{Addr, DepsMut, Order, Storage}; +use cw_storage_plus::Item; use mixnet_contract_common::error::MixnetContractError; -use mixnet_contract_common::PendingEpochEventKind; +use mixnet_contract_common::{ContractState, ContractStateParams, PendingEpochEventKind}; +use serde::{Deserialize, Serialize}; fn ensure_no_pending_proxy_events(storage: &dyn Storage) -> Result<(), MixnetContractError> { let last_executed = interval_storage::LAST_PROCESSED_EPOCH_EVENT.load(storage)?; @@ -49,3 +53,29 @@ pub(crate) fn vesting_purge(deps: DepsMut) -> Result<(), MixnetContractError> { Ok(()) } + +pub(crate) fn explicit_contract_admin(deps: DepsMut) -> Result<(), MixnetContractError> { + #[derive(Deserialize, Serialize)] + pub struct OldContractState { + pub owner: Addr, + pub rewarding_validator_address: Addr, + pub vesting_contract_address: Addr, + pub rewarding_denom: String, + pub params: ContractStateParams, + } + + let old_state_storage = Item::::new(CONTRACT_STATE_KEY); + let old_state = old_state_storage.load(deps.storage)?; + + mixnet_params_storage::initialise_storage( + deps, + ContractState { + rewarding_validator_address: old_state.rewarding_validator_address, + vesting_contract_address: old_state.vesting_contract_address, + rewarding_denom: old_state.rewarding_denom, + params: old_state.params, + }, + old_state.owner, + )?; + Ok(()) +} diff --git a/contracts/mixnet/src/rewards/transactions.rs b/contracts/mixnet/src/rewards/transactions.rs index 3f9b0e329a..f772dca800 100644 --- a/contracts/mixnet/src/rewards/transactions.rs +++ b/contracts/mixnet/src/rewards/transactions.rs @@ -6,13 +6,13 @@ use crate::delegations::storage as delegations_storage; use crate::interval::storage as interval_storage; use crate::interval::storage::{push_new_epoch_event, push_new_interval_event}; use crate::mixnet_contract_settings::storage as mixnet_params_storage; +use crate::mixnet_contract_settings::storage::ADMIN; use crate::mixnodes::helpers::get_mixnode_details_by_owner; use crate::mixnodes::storage as mixnodes_storage; use crate::rewards::helpers; use crate::rewards::helpers::update_and_save_last_rewarded; use crate::support::helpers::{ - ensure_bonded, ensure_can_advance_epoch, ensure_epoch_in_progress_state, ensure_is_owner, - AttachSendTokens, + ensure_bonded, ensure_can_advance_epoch, ensure_epoch_in_progress_state, AttachSendTokens, }; use cosmwasm_std::{DepsMut, Env, MessageInfo, Response}; use mixnet_contract_common::error::MixnetContractError; @@ -227,7 +227,7 @@ pub(crate) fn try_update_active_set_size( active_set_size: u32, force_immediately: bool, ) -> Result { - ensure_is_owner(info.sender, deps.storage)?; + ADMIN.assert_admin(deps.as_ref(), &info.sender)?; let mut rewarding_params = storage::REWARDING_PARAMS.load(deps.storage)?; if active_set_size == 0 { @@ -273,7 +273,7 @@ pub(crate) fn try_update_rewarding_params( updated_params: IntervalRewardingParamsUpdate, force_immediately: bool, ) -> Result { - ensure_is_owner(info.sender, deps.storage)?; + ADMIN.assert_admin(deps.as_ref(), &info.sender)?; if !updated_params.contains_updates() { return Err(MixnetContractError::EmptyParamsChangeMsg); @@ -1796,6 +1796,7 @@ pub mod tests { #[cfg(test)] mod updating_active_set { + use cw_controllers::AdminError::NotAdmin; use mixnet_contract_common::EpochStatus; use crate::support::tests::test_helpers::TestSetup; @@ -1858,10 +1859,10 @@ pub mod tests { 42, false, ); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let res = try_update_active_set_size(test.deps_mut(), env.clone(), random, 42, false); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let res = try_update_active_set_size(test.deps_mut(), env, owner, 42, false); assert!(res.is_ok()) @@ -2002,6 +2003,7 @@ pub mod tests { #[cfg(test)] mod updating_rewarding_params { use cosmwasm_std::Decimal; + use cw_controllers::AdminError::NotAdmin; use mixnet_contract_common::EpochStatus; @@ -2085,11 +2087,11 @@ pub mod tests { update, false, ); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let res = try_update_rewarding_params(test.deps_mut(), env.clone(), random, update, false); - assert_eq!(res, Err(MixnetContractError::Unauthorized)); + assert_eq!(res, Err(MixnetContractError::Admin(NotAdmin {}))); let res = try_update_rewarding_params(test.deps_mut(), env, owner, update, false); assert!(res.is_ok()) diff --git a/contracts/mixnet/src/support/helpers.rs b/contracts/mixnet/src/support/helpers.rs index 09738cea81..19ddf2bb6e 100644 --- a/contracts/mixnet/src/support/helpers.rs +++ b/contracts/mixnet/src/support/helpers.rs @@ -194,20 +194,6 @@ pub(crate) fn ensure_can_advance_epoch( Ok(epoch_status) } -pub(crate) fn ensure_is_owner( - sender: Addr, - storage: &dyn Storage, -) -> Result<(), MixnetContractError> { - if sender - != crate::mixnet_contract_settings::storage::CONTRACT_STATE - .load(storage)? - .owner - { - return Err(MixnetContractError::Unauthorized); - } - Ok(()) -} - pub(crate) fn ensure_bonded(bond: &MixNodeBond) -> Result<(), MixnetContractError> { if bond.is_unbonding { return Err(MixnetContractError::MixnodeIsUnbonding { diff --git a/contracts/mixnet/src/support/tests/mod.rs b/contracts/mixnet/src/support/tests/mod.rs index 976138fdc2..dee121b2f0 100644 --- a/contracts/mixnet/src/support/tests/mod.rs +++ b/contracts/mixnet/src/support/tests/mod.rs @@ -105,10 +105,11 @@ pub mod test_helpers { let deps = init_contract(); let rewarding_validator_address = rewarding_validator_address(deps.as_ref().storage).unwrap(); - let owner = mixnet_params_storage::CONTRACT_STATE - .load(deps.as_ref().storage) + let owner = mixnet_params_storage::ADMIN + .query_admin(deps.as_ref()) .unwrap() - .owner; + .admin + .unwrap(); TestSetup { deps, diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 074ff08f97..382b526b9f 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -3281,6 +3281,7 @@ dependencies = [ "bs58 0.4.0", "cosmwasm-schema", "cosmwasm-std", + "cw-controllers", "humantime-serde", "log", "nym-contracts-common", From 07c80e5150a2a629707425802d283c67c95663cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 28 Aug 2024 16:31:39 +0100 Subject: [PATCH 21/41] naming consistency --- .../src/nyxd/contract_traits/mixnet_signing_client.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs index 00b0755477..f84becb55f 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_signing_client.rs @@ -761,7 +761,6 @@ where mod tests { use super::*; use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue}; - use nym_mixnet_contract_common::ExecuteMsg; // it's enough that this compiles and clippy is happy about it #[allow(dead_code)] @@ -770,7 +769,7 @@ mod tests { msg: MixnetExecuteMsg, ) { match msg { - ExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(), + MixnetExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(), MixnetExecuteMsg::AssignNodeLayer { mix_id, layer } => { client.assign_node_layer(mix_id, layer, None).ignore() } From 74cd73a58f886cba2f5a3e14630c6aeebb909219 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 28 Aug 2024 17:35:37 +0200 Subject: [PATCH 22/41] fmt --- common/network-defaults/src/mainnet.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/network-defaults/src/mainnet.rs b/common/network-defaults/src/mainnet.rs index ffbbe8d265..8ebe2e044e 100644 --- a/common/network-defaults/src/mainnet.rs +++ b/common/network-defaults/src/mainnet.rs @@ -17,8 +17,8 @@ pub const MIXNET_CONTRACT_ADDRESS: &str = "n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr"; pub const VESTING_CONTRACT_ADDRESS: &str = "n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw"; -pub const ECASH_CONTRACT_ADDRESS: &str = -"n1r7s6aksyc6pqardx88k3rkgfagwvj4z4zum9mmz2sfk3zm2mha0sd4dnun"; +pub const ECASH_CONTRACT_ADDRESS: &str = + "n1r7s6aksyc6pqardx88k3rkgfagwvj4z4zum9mmz2sfk3zm2mha0sd4dnun"; pub const GROUP_CONTRACT_ADDRESS: &str = "n1e2zq4886zzewpvpucmlw8v9p7zv692f6yck4zjzxh699dkcmlrfqk2knsr"; pub const MULTISIG_CONTRACT_ADDRESS: &str = From bb7a8e84e49cf58b5be807f04bc767947014ef72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Tue, 3 Sep 2024 15:24:49 +0200 Subject: [PATCH 23/41] Eliminate cancel unsafe sig awaiting (#4834) * Eliminate cancel unsafe sig awaiting * Fix wasm build * Simplify spawn call * Fix wasm lint --- Cargo.lock | 1 + .../gateway-client/src/client/mod.rs | 2 + common/gateway-requests/Cargo.toml | 1 + .../src/registration/handshake/client.rs | 3 + .../src/registration/handshake/error.rs | 2 + .../src/registration/handshake/gateway.rs | 4 +- .../src/registration/handshake/mod.rs | 8 +- .../src/registration/handshake/state.rs | 99 ++++++--- common/task/src/manager.rs | 12 -- .../websocket/connection_handler/fresh.rs | 194 ++++++++++-------- .../websocket/connection_handler/mod.rs | 43 ++-- .../client_handling/websocket/listener.rs | 5 +- 12 files changed, 218 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad525671a6..03acc93774 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5069,6 +5069,7 @@ dependencies = [ "nym-crypto", "nym-pemstore", "nym-sphinx", + "nym-task", "rand", "serde", "serde_json", diff --git a/common/client-libs/gateway-client/src/client/mod.rs b/common/client-libs/gateway-client/src/client/mod.rs index e544a610b6..d899ec2928 100644 --- a/common/client-libs/gateway-client/src/client/mod.rs +++ b/common/client-libs/gateway-client/src/client/mod.rs @@ -417,6 +417,8 @@ impl GatewayClient { self.local_identity.as_ref(), self.gateway_identity, self.cfg.bandwidth.require_tickets, + #[cfg(not(target_arch = "wasm32"))] + self.task_client.clone(), ) .await .map_err(GatewayClientError::RegistrationFailure), diff --git a/common/gateway-requests/Cargo.toml b/common/gateway-requests/Cargo.toml index c1dadc4732..72a2bdfe9d 100644 --- a/common/gateway-requests/Cargo.toml +++ b/common/gateway-requests/Cargo.toml @@ -24,6 +24,7 @@ zeroize = { workspace = true } nym-crypto = { path = "../crypto" } nym-pemstore = { path = "../pemstore" } nym-sphinx = { path = "../nymsphinx" } +nym-task = { path = "../task" } nym-credentials = { path = "../credentials" } nym-credentials-interface = { path = "../credentials-interface" } diff --git a/common/gateway-requests/src/registration/handshake/client.rs b/common/gateway-requests/src/registration/handshake/client.rs index edb30ebf20..902a520bca 100644 --- a/common/gateway-requests/src/registration/handshake/client.rs +++ b/common/gateway-requests/src/registration/handshake/client.rs @@ -25,6 +25,7 @@ impl<'a> ClientHandshake<'a> { identity: &'a nym_crypto::asymmetric::identity::KeyPair, gateway_pubkey: identity::PublicKey, expects_credential_usage: bool, + #[cfg(not(target_arch = "wasm32"))] shutdown: nym_task::TaskClient, ) -> Self where S: Stream + Sink + Unpin + Send + 'a, @@ -35,6 +36,8 @@ impl<'a> ClientHandshake<'a> { identity, Some(gateway_pubkey), expects_credential_usage, + #[cfg(not(target_arch = "wasm32"))] + shutdown, ); ClientHandshake { diff --git a/common/gateway-requests/src/registration/handshake/error.rs b/common/gateway-requests/src/registration/handshake/error.rs index 8fee78fd38..6e82ef040c 100644 --- a/common/gateway-requests/src/registration/handshake/error.rs +++ b/common/gateway-requests/src/registration/handshake/error.rs @@ -25,6 +25,8 @@ pub enum HandshakeError { MalformedRequest, #[error("sent request was malformed")] HandshakeFailure, + #[error("received shutdown")] + ReceivedShutdown, #[error("timed out waiting for a handshake message")] Timeout, diff --git a/common/gateway-requests/src/registration/handshake/gateway.rs b/common/gateway-requests/src/registration/handshake/gateway.rs index bb0003d0a3..a42851a320 100644 --- a/common/gateway-requests/src/registration/handshake/gateway.rs +++ b/common/gateway-requests/src/registration/handshake/gateway.rs @@ -8,6 +8,7 @@ use futures::future::BoxFuture; use futures::task::{Context, Poll}; use futures::{Future, Sink, Stream}; use nym_crypto::asymmetric::encryption; +use nym_task::TaskClient; use rand::{CryptoRng, RngCore}; use std::pin::Pin; use tungstenite::Message as WsMessage; @@ -22,11 +23,12 @@ impl<'a> GatewayHandshake<'a> { ws_stream: &'a mut S, identity: &'a nym_crypto::asymmetric::identity::KeyPair, received_init_payload: Vec, + shutdown: TaskClient, ) -> Self where S: Stream + Sink + Unpin + Send + 'a, { - let mut state = State::new(rng, ws_stream, identity, None, true); + let mut state = State::new(rng, ws_stream, identity, None, true, shutdown); GatewayHandshake { handshake_future: Box::pin(async move { // If any step along the way failed (that are non-network related), diff --git a/common/gateway-requests/src/registration/handshake/mod.rs b/common/gateway-requests/src/registration/handshake/mod.rs index 4e21fcfc0d..d3faec7903 100644 --- a/common/gateway-requests/src/registration/handshake/mod.rs +++ b/common/gateway-requests/src/registration/handshake/mod.rs @@ -8,6 +8,8 @@ use self::gateway::GatewayHandshake; pub use self::shared_key::{SharedKeySize, SharedKeys}; use futures::{Sink, Stream}; use nym_crypto::asymmetric::identity; +#[cfg(not(target_arch = "wasm32"))] +use nym_task::TaskClient; use rand::{CryptoRng, RngCore}; use tungstenite::{Error as WsError, Message as WsMessage}; @@ -31,6 +33,7 @@ pub async fn client_handshake<'a, S>( identity: &'a identity::KeyPair, gateway_pubkey: identity::PublicKey, expects_credential_usage: bool, + #[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient, ) -> Result where S: Stream + Sink + Unpin + Send + 'a, @@ -41,6 +44,8 @@ where identity, gateway_pubkey, expects_credential_usage, + #[cfg(not(target_arch = "wasm32"))] + shutdown, ) .await } @@ -51,11 +56,12 @@ pub async fn gateway_handshake<'a, S>( ws_stream: &'a mut S, identity: &'a identity::KeyPair, received_init_payload: Vec, + shutdown: TaskClient, ) -> Result where S: Stream + Sink + Unpin + Send + 'a, { - GatewayHandshake::new(rng, ws_stream, identity, received_init_payload).await + GatewayHandshake::new(rng, ws_stream, identity, received_init_payload, shutdown).await } /* diff --git a/common/gateway-requests/src/registration/handshake/state.rs b/common/gateway-requests/src/registration/handshake/state.rs index 328b5d59cb..70cd48620c 100644 --- a/common/gateway-requests/src/registration/handshake/state.rs +++ b/common/gateway-requests/src/registration/handshake/state.rs @@ -13,6 +13,8 @@ use nym_crypto::{ symmetric::stream_cipher, }; use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm}; +#[cfg(not(target_arch = "wasm32"))] +use nym_task::TaskClient; use rand::{CryptoRng, RngCore}; use tracing::log::*; @@ -48,6 +50,10 @@ pub(crate) struct State<'a, S> { // this field is really out of place here, however, we need to propagate this information somehow // in order to establish correct protocol for backwards compatibility reasons expects_credential_usage: bool, + + // channel to receive shutdown signal + #[cfg(not(target_arch = "wasm32"))] + shutdown: TaskClient, } impl<'a, S> State<'a, S> { @@ -57,6 +63,7 @@ impl<'a, S> State<'a, S> { identity: &'a identity::KeyPair, remote_pubkey: Option, expects_credential_usage: bool, + #[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient, ) -> Self { let ephemeral_keypair = encryption::KeyPair::new(rng); State { @@ -66,6 +73,8 @@ impl<'a, S> State<'a, S> { remote_pubkey, derived_shared_keys: None, expects_credential_usage, + #[cfg(not(target_arch = "wasm32"))] + shutdown, } } @@ -199,46 +208,76 @@ impl<'a, S> State<'a, S> { self.remote_pubkey = Some(remote_pubkey) } + fn on_wg_msg(msg: Option) -> Result>, HandshakeError> { + let Some(msg) = msg else { + return Err(HandshakeError::ClosedStream); + }; + + let Ok(msg) = msg else { + return Err(HandshakeError::NetworkError); + }; + match msg { + WsMessage::Text(ref ws_msg) => { + match types::RegistrationHandshake::from_str(ws_msg) { + Ok(reg_handshake_msg) => { + match reg_handshake_msg { + // hehe, that's a bit disgusting that the type system requires we explicitly ignore the + // protocol_version field that we actually never attach at this point + // yet another reason for the overdue refactor + types::RegistrationHandshake::HandshakePayload { data, .. } => { + Ok(Some(data)) + } + types::RegistrationHandshake::HandshakeError { message } => { + Err(HandshakeError::RemoteError(message)) + } + } + } + Err(_) => { + error!("Received a non-handshake message during the registration handshake! It's getting dropped. The received content was: '{msg}'"); + Ok(None) + } + } + } + _ => { + error!("Received non-text message during registration handshake"); + Ok(None) + } + } + } + + #[cfg(not(target_arch = "wasm32"))] async fn _receive_handshake_message(&mut self) -> Result, HandshakeError> where S: Stream + Unpin, { loop { - let Some(msg) = self.ws_stream.next().await else { - return Err(HandshakeError::ClosedStream); - }; - - let Ok(msg) = msg else { - return Err(HandshakeError::NetworkError); - }; - - match msg { - WsMessage::Text(ref ws_msg) => { - match types::RegistrationHandshake::from_str(ws_msg) { - Ok(reg_handshake_msg) => { - return match reg_handshake_msg { - // hehe, that's a bit disgusting that the type system requires we explicitly ignore the - // protocol_version field that we actually never attach at this point - // yet another reason for the overdue refactor - types::RegistrationHandshake::HandshakePayload { data, .. } => { - Ok(data) - } - types::RegistrationHandshake::HandshakeError { message } => { - Err(HandshakeError::RemoteError(message)) - } - }; - } - Err(_) => { - error!("Received a non-handshake message during the registration handshake! It's getting dropped. The received content was: '{msg}'"); - continue; - } - } + tokio::select! { + biased; + _ = self.shutdown.recv() => return Err(HandshakeError::ReceivedShutdown), + msg = self.ws_stream.next() => { + let Some(ret) = Self::on_wg_msg(msg)? else { + continue; + }; + return Ok(ret); } - _ => error!("Received non-text message during registration handshake"), } } } + #[cfg(target_arch = "wasm32")] + async fn _receive_handshake_message(&mut self) -> Result, HandshakeError> + where + S: Stream + Unpin, + { + loop { + let msg = self.ws_stream.next().await; + let Some(ret) = Self::on_wg_msg(msg)? else { + continue; + }; + return Ok(ret); + } + } + pub(crate) async fn receive_handshake_message(&mut self) -> Result, HandshakeError> where S: Stream + Unpin, diff --git a/common/task/src/manager.rs b/common/task/src/manager.rs index ab03870dc0..8a4c21a311 100644 --- a/common/task/src/manager.rs +++ b/common/task/src/manager.rs @@ -3,7 +3,6 @@ use futures::{future::pending, FutureExt, SinkExt, StreamExt}; use log::{log, Level}; -use std::future::Future; use std::sync::atomic::{AtomicBool, Ordering}; use std::{error::Error, time::Duration}; use tokio::sync::{ @@ -368,17 +367,6 @@ impl TaskClient { self.named(name) } - pub async fn run_future(&mut self, fut: Fut) -> Option - where - Fut: Future, - { - tokio::select! { - biased; - _ = self.recv() => None, - res = fut => Some(res) - } - } - // Create a dummy that will never report that we should shutdown. pub fn dummy() -> TaskClient { let (_notify_tx, notify_rx) = watch::channel(()); diff --git a/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs b/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs index 0986532896..fc5f453e25 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs @@ -20,6 +20,7 @@ use nym_gateway_requests::{ }; use nym_mixnet_client::forwarder::MixForwardingSender; use nym_sphinx::DestinationAddressBytes; +use nym_task::TaskClient; use rand::{CryptoRng, Rng}; use std::net::SocketAddr; use std::time::Duration; @@ -111,6 +112,9 @@ pub(crate) enum InitialAuthenticationError { #[error("failed to upgrade the client handler: {source}")] HandlerUpgradeFailure { source: RequestHandlingError }, + + #[error("received shutdown")] + ReceivedShutdown, } impl InitialAuthenticationError { @@ -127,6 +131,7 @@ pub(crate) struct FreshHandler { pub(crate) outbound_mix_sender: MixForwardingSender, pub(crate) socket_connection: SocketStream, pub(crate) peer_address: SocketAddr, + pub(crate) shutdown: TaskClient, // currently unused (but populated) pub(crate) negotiated_protocol: Option, @@ -149,6 +154,7 @@ where active_clients_store: ActiveClientsStore, shared_state: CommonHandlerState, peer_address: SocketAddr, + shutdown: TaskClient, ) -> Self { FreshHandler { rng, @@ -158,6 +164,7 @@ where peer_address, negotiated_protocol: None, shared_state, + shutdown, } } @@ -201,6 +208,7 @@ where ws_stream, self.shared_state.local_identity.as_ref(), init_msg, + self.shutdown.clone(), ) .await } @@ -720,111 +728,125 @@ where { trace!("Started waiting for authenticate/register request..."); - while let Some(msg) = self.read_websocket_message().await { - let msg = match msg { - Ok(msg) => msg, - Err(source) => { - debug!("failed to obtain message from websocket stream! stopping connection handler: {source}"); - return Err(InitialAuthenticationError::FailedToReadMessage { source }); - } - }; + let mut shutdown = self.shutdown.clone(); + loop { + tokio::select! { + biased; + _ = shutdown.recv() => { + trace!("received shutdown signal while performing initial authentication"); + return Err(InitialAuthenticationError::ReceivedShutdown); + }, + msg = self.read_websocket_message() => { + let Some(msg) = msg else { + break; + }; - if msg.is_close() { - return Err(InitialAuthenticationError::CloseMessage); - } + let msg = match msg { + Ok(msg) => msg, + Err(source) => { + debug!("failed to obtain message from websocket stream! stopping connection handler: {source}"); + return Err(InitialAuthenticationError::FailedToReadMessage { source }); + } + }; - // ONLY handle 'Authenticate' or 'Register' requests, ignore everything else - match msg { - // we have explicitly checked for close message - Message::Close(_) => unreachable!(), - Message::Text(text_msg) => { - let (mix_sender, mix_receiver) = mpsc::unbounded(); - return match self.handle_initial_authentication_request(text_msg).await { - Err(err) => { - debug!("authentication failure: {err}"); + if msg.is_close() { + return Err(InitialAuthenticationError::CloseMessage); + } - // try to send error to the client - if let Err(source) = - self.send_websocket_message(err.to_error_message()).await + // ONLY handle 'Authenticate' or 'Register' requests, ignore everything else + match msg { + // we have explicitly checked for close message + Message::Close(_) => unreachable!(), + Message::Text(text_msg) => { + let (mix_sender, mix_receiver) = mpsc::unbounded(); + return match self.handle_initial_authentication_request(text_msg).await { + Err(err) => { + debug!("authentication failure: {err}"); + + // try to send error to the client + if let Err(source) = + self.send_websocket_message(err.to_error_message()).await + { + debug!("Failed to send authentication error response: {source}"); + return Err(InitialAuthenticationError::ErrorResponseSendFailure { + source, + }); + } + // return the underlying error + Err(err) + } + Ok(auth_result) => { + // try to send auth response back to the client + if let Err(source) = self + .send_websocket_message(auth_result.server_response.into()) + .await + { + debug!("Failed to send authentication response: {source}"); + return Err(InitialAuthenticationError::ResponseSendFailure { + source, + }); + } + + if let Some(client_details) = auth_result.client_details { + // Channel for handlers to ask other handlers if they are still active. + let (is_active_request_sender, is_active_request_receiver) = + mpsc::unbounded(); + self.active_clients_store.insert_remote( + client_details.address, + mix_sender, + is_active_request_sender, + ); + AuthenticatedHandler::upgrade( + self, + client_details, + mix_receiver, + is_active_request_receiver, + ) + .await + .map_err(|source| { + InitialAuthenticationError::HandlerUpgradeFailure { source } + }) + } else { + // honestly, it's been so long I don't remember under what conditions its possible (if at all) + // to have empty client details + Err(InitialAuthenticationError::EmptyClientDetails) + } + } + }; + } + Message::Binary(_) => { + // perhaps logging level should be reduced here, let's leave it for now and see what happens + // if client is working correctly, this should have never happened + debug!("possibly received a sphinx packet without prior authentication. Request is going to be ignored"); + if let Err(source) = self + .send_websocket_message( + ServerResponse::new_error( + "binary request without prior authentication", + ) + .into(), + ) + .await { - debug!("Failed to send authentication error response: {source}"); return Err(InitialAuthenticationError::ErrorResponseSendFailure { source, }); } - // return the underlying error - Err(err) + return Err(InitialAuthenticationError::BinaryRequestWithoutAuthentication); } - Ok(auth_result) => { - // try to send auth response back to the client - if let Err(source) = self - .send_websocket_message(auth_result.server_response.into()) - .await - { - debug!("Failed to send authentication response: {source}"); - return Err(InitialAuthenticationError::ResponseSendFailure { - source, - }); - } - if let Some(client_details) = auth_result.client_details { - // Channel for handlers to ask other handlers if they are still active. - let (is_active_request_sender, is_active_request_receiver) = - mpsc::unbounded(); - self.active_clients_store.insert_remote( - client_details.address, - mix_sender, - is_active_request_sender, - ); - AuthenticatedHandler::upgrade( - self, - client_details, - mix_receiver, - is_active_request_receiver, - ) - .await - .map_err(|source| { - InitialAuthenticationError::HandlerUpgradeFailure { source } - }) - } else { - // honestly, it's been so long I don't remember under what conditions its possible (if at all) - // to have empty client details - Err(InitialAuthenticationError::EmptyClientDetails) - } - } + _ => continue, }; } - Message::Binary(_) => { - // perhaps logging level should be reduced here, let's leave it for now and see what happens - // if client is working correctly, this should have never happened - debug!("possibly received a sphinx packet without prior authentication. Request is going to be ignored"); - if let Err(source) = self - .send_websocket_message( - ServerResponse::new_error( - "binary request without prior authentication", - ) - .into(), - ) - .await - { - return Err(InitialAuthenticationError::ErrorResponseSendFailure { - source, - }); - } - return Err(InitialAuthenticationError::BinaryRequestWithoutAuthentication); - } - - _ => continue, - }; + } } Err(InitialAuthenticationError::ClosedConnection) } - pub(crate) async fn start_handling(self, shutdown: nym_task::TaskClient) + pub(crate) async fn start_handling(self) where S: AsyncRead + AsyncWrite + Unpin + Send, { - super::handle_connection(self, shutdown).await + super::handle_connection(self).await } } diff --git a/gateway/src/node/client_handling/websocket/connection_handler/mod.rs b/gateway/src/node/client_handling/websocket/connection_handler/mod.rs index 656ac91c65..5eca9ad070 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/mod.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/mod.rs @@ -8,7 +8,6 @@ use nym_gateway_requests::registration::handshake::SharedKeys; use nym_gateway_requests::ServerResponse; use nym_gateway_storage::Storage; use nym_sphinx::DestinationAddressBytes; -use nym_task::TaskClient; use rand::{CryptoRng, Rng}; use std::time::Duration; use time::OffsetDateTime; @@ -24,6 +23,8 @@ pub(crate) mod authenticated; pub(crate) mod ecash; mod fresh; +const WEBSOCKET_HANDSHAKE_TIMEOUT: Duration = Duration::from_millis(1_500); + // TODO: note for my future self to consider the following idea: // split the socket connection into sink and stream // stream will be for reading explicit requests @@ -87,53 +88,47 @@ impl InitialAuthResult { // imo there's no point in including the peer address in anything higher than debug #[instrument(level = "debug", skip_all, fields(peer = %handle.peer_address))] -pub(crate) async fn handle_connection( - mut handle: FreshHandler, - mut shutdown: TaskClient, -) where +pub(crate) async fn handle_connection(mut handle: FreshHandler) +where R: Rng + CryptoRng, S: AsyncRead + AsyncWrite + Unpin + Send, St: Storage + Clone + 'static, { // If the connection handler abruptly stops, we shouldn't signal global shutdown - shutdown.mark_as_success(); + handle.shutdown.mark_as_success(); - match shutdown - .run_future(handle.perform_websocket_handshake()) - .await + match tokio::time::timeout( + WEBSOCKET_HANDSHAKE_TIMEOUT, + handle.perform_websocket_handshake(), + ) + .await { - None => { - trace!("received shutdown signal while performing websocket handshake"); + Err(timeout_err) => { + warn!("websocket handshake timedout: {timeout_err}"); return; } - Some(Err(err)) => { + Ok(Err(err)) => { warn!("Failed to complete WebSocket handshake: {err}. Stopping the handler"); return; } - _ => (), + _ => {} } trace!("Managed to perform websocket handshake!"); - match shutdown - .run_future(handle.perform_initial_authentication()) - .await - { - None => { - trace!("received shutdown signal while performing initial authentication"); - return; - } + let shutdown = handle.shutdown.clone(); + match handle.perform_initial_authentication().await { // For storage error, we want to print the extended storage error, but without // including it in the error that's returned to the clients - Some(Err(InitialAuthenticationError::StorageError(err))) => { + Err(InitialAuthenticationError::StorageError(err)) => { warn!("authentication has failed: {err}"); return; } - Some(Err(err)) => { + Err(err) => { warn!("authentication has failed: {err}"); return; } - Some(Ok(auth_handle)) => auth_handle.listen_for_requests(shutdown).await, + Ok(auth_handle) => auth_handle.listen_for_requests(shutdown).await, } trace!("The handler is done!"); diff --git a/gateway/src/node/client_handling/websocket/listener.rs b/gateway/src/node/client_handling/websocket/listener.rs index 8c0b98a440..be3c6c51a2 100644 --- a/gateway/src/node/client_handling/websocket/listener.rs +++ b/gateway/src/node/client_handling/websocket/listener.rs @@ -54,6 +54,7 @@ where connection = tcp_listener.accept() => { match connection { Ok((socket, remote_addr)) => { + let shutdown = shutdown.clone().named(format!("ClientConnectionHandler_{remote_addr}")); trace!("received a socket connection from {remote_addr}"); // TODO: I think we *REALLY* need a mechanism for having a maximum number of connected // clients or spawned tokio tasks -> perhaps a worker system? @@ -64,9 +65,9 @@ where active_clients_store.clone(), self.shared_state.clone(), remote_addr, + shutdown, ); - let shutdown = shutdown.clone().named(format!("ClientConnectionHandler_{remote_addr}")); - tokio::spawn(async move { handle.start_handling(shutdown).await }); + tokio::spawn(handle.start_handling()); } Err(err) => warn!("failed to get client: {err}"), } From 7b4dc78f4117e7f6b4adba7d4aa3f83329982b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Tue, 3 Sep 2024 15:25:05 +0200 Subject: [PATCH 24/41] Remove wireguard feature flag and pass runtime enabled flag (#4839) * Remove wireguard feature flag * Use wg enabled runtime flag * Fix unintended flag removal --- .github/workflows/ci-build-upload-binaries.yml | 4 ---- .github/workflows/ci-build.yml | 12 +++++------- .github/workflows/publish-nym-binaries.yml | 4 ---- common/gateway-storage/Cargo.toml | 7 ++----- common/gateway-storage/src/lib.rs | 11 ----------- common/gateway-storage/src/models.rs | 3 --- common/wireguard/Cargo.toml | 2 +- gateway/Cargo.toml | 9 ++------- gateway/src/error.rs | 6 ++---- gateway/src/node/mod.rs | 18 ++++++++---------- nym-node/Cargo.toml | 10 +++++----- nym-node/src/node/mod.rs | 10 ++++++---- 12 files changed, 31 insertions(+), 65 deletions(-) diff --git a/.github/workflows/ci-build-upload-binaries.yml b/.github/workflows/ci-build-upload-binaries.yml index 00c28191bd..cd0067e7d4 100644 --- a/.github/workflows/ci-build-upload-binaries.yml +++ b/.github/workflows/ci-build-upload-binaries.yml @@ -62,10 +62,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: diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 19d5fc327e..268de52c55 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -73,29 +73,27 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - # Enable wireguard by default on linux only - args: --workspace --features wireguard - name: Build all examples if: matrix.os == 'custom-linux' uses: actions-rs/cargo@v1 with: command: build - args: --workspace --examples --features wireguard + args: --workspace --examples - name: Run all tests if: matrix.os == 'custom-linux' uses: actions-rs/cargo@v1 with: command: test - args: --workspace --features wireguard + args: --workspace - name: Run expensive tests if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && matrix.os == 'custom-linux' uses: actions-rs/cargo@v1 with: command: test - args: --workspace --features wireguard -- --ignored + args: --workspace -- --ignored - name: Annotate with clippy checks if: matrix.os == 'custom-linux' @@ -103,10 +101,10 @@ jobs: continue-on-error: true with: token: ${{ secrets.GITHUB_TOKEN }} - args: --workspace --features wireguard + args: --workspace - name: Clippy uses: actions-rs/cargo@v1 with: command: clippy - args: --workspace --all-targets --features wireguard -- -D warnings + args: --workspace --all-targets -- -D warnings diff --git a/.github/workflows/publish-nym-binaries.yml b/.github/workflows/publish-nym-binaries.yml index be70c514ba..32cc171ac2 100644 --- a/.github/workflows/publish-nym-binaries.yml +++ b/.github/workflows/publish-nym-binaries.yml @@ -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: diff --git a/common/gateway-storage/Cargo.toml b/common/gateway-storage/Cargo.toml index eb18f1444e..26b2be56a1 100644 --- a/common/gateway-storage/Cargo.toml +++ b/common/gateway-storage/Cargo.toml @@ -10,8 +10,8 @@ license.workspace = true [dependencies] async-trait = { workspace = true } -bincode = { workspace = true, optional = true } -defguard_wireguard_rs = { workspace = true, optional = true } +bincode = { workspace = true } +defguard_wireguard_rs = { workspace = true } log = { workspace = true } sqlx = { workspace = true, features = [ "runtime-tokio-rustls", @@ -36,6 +36,3 @@ sqlx = { workspace = true, features = [ "macros", "migrate", ] } - -[features] -wireguard = ["defguard_wireguard_rs", "bincode"] diff --git a/common/gateway-storage/src/lib.rs b/common/gateway-storage/src/lib.rs index 7d3611fccf..d6274ae854 100644 --- a/common/gateway-storage/src/lib.rs +++ b/common/gateway-storage/src/lib.rs @@ -25,7 +25,6 @@ mod inboxes; pub(crate) mod models; mod shared_keys; mod tickets; -#[cfg(feature = "wireguard")] mod wireguard_peers; #[async_trait] @@ -217,7 +216,6 @@ pub trait Storage: Send + Sync { /// /// * `peer`: wireguard peer data to be stored /// * `suspended`: if peer exists, but it's currently suspended - #[cfg(feature = "wireguard")] async fn insert_wireguard_peer( &self, peer: &defguard_wireguard_rs::host::Peer, @@ -229,14 +227,12 @@ pub trait Storage: Send + Sync { /// # Arguments /// /// * `peer_public_key`: wireguard public key of the peer to be retrieved. - #[cfg(feature = "wireguard")] async fn get_wireguard_peer( &self, peer_public_key: &str, ) -> Result, StorageError>; /// Retrieves all wireguard peers. - #[cfg(feature = "wireguard")] async fn get_all_wireguard_peers(&self) -> Result, StorageError>; /// Remove a wireguard peer from the storage. @@ -244,7 +240,6 @@ pub trait Storage: Send + Sync { /// # Arguments /// /// * `peer_public_key`: wireguard public key of the peer to be removed. - #[cfg(feature = "wireguard")] async fn remove_wireguard_peer(&self, peer_public_key: &str) -> Result<(), StorageError>; } @@ -255,7 +250,6 @@ pub struct PersistentStorage { inbox_manager: InboxManager, bandwidth_manager: BandwidthManager, ticket_manager: TicketStorageManager, - #[cfg(feature = "wireguard")] wireguard_peer_manager: wireguard_peers::WgPeerManager, } @@ -300,7 +294,6 @@ impl PersistentStorage { // the cloning here are cheap as connection pool is stored behind an Arc Ok(PersistentStorage { - #[cfg(feature = "wireguard")] wireguard_peer_manager: wireguard_peers::WgPeerManager::new(connection_pool.clone()), shared_key_manager: SharedKeysManager::new(connection_pool.clone()), inbox_manager: InboxManager::new(connection_pool.clone(), message_retrieval_limit), @@ -620,7 +613,6 @@ impl Storage for PersistentStorage { Ok(self.ticket_manager.get_epoch_signers(epoch_id).await?) } - #[cfg(feature = "wireguard")] async fn insert_wireguard_peer( &self, peer: &defguard_wireguard_rs::host::Peer, @@ -632,7 +624,6 @@ impl Storage for PersistentStorage { Ok(()) } - #[cfg(feature = "wireguard")] async fn get_wireguard_peer( &self, peer_public_key: &str, @@ -644,13 +635,11 @@ impl Storage for PersistentStorage { Ok(peer) } - #[cfg(feature = "wireguard")] async fn get_all_wireguard_peers(&self) -> Result, StorageError> { let ret = self.wireguard_peer_manager.retrieve_all_peers().await?; Ok(ret) } - #[cfg(feature = "wireguard")] async fn remove_wireguard_peer(&self, peer_public_key: &str) -> Result<(), StorageError> { self.wireguard_peer_manager .remove_peer(peer_public_key) diff --git a/common/gateway-storage/src/models.rs b/common/gateway-storage/src/models.rs index e1973ac1e3..dc0229d1f3 100644 --- a/common/gateway-storage/src/models.rs +++ b/common/gateway-storage/src/models.rs @@ -72,7 +72,6 @@ impl TryFrom for ClientTicket { } } -#[cfg(feature = "wireguard")] #[derive(Debug, Clone, FromRow)] pub struct WireguardPeer { pub public_key: String, @@ -87,7 +86,6 @@ pub struct WireguardPeer { pub suspended: bool, } -#[cfg(feature = "wireguard")] impl From for WireguardPeer { fn from(value: defguard_wireguard_rs::host::Peer) -> Self { WireguardPeer { @@ -120,7 +118,6 @@ impl From for WireguardPeer { } } -#[cfg(feature = "wireguard")] impl TryFrom for defguard_wireguard_rs::host::Peer { type Error = crate::error::StorageError; diff --git a/common/wireguard/Cargo.toml b/common/wireguard/Cargo.toml index 18759fa641..f90708a68d 100644 --- a/common/wireguard/Cargo.toml +++ b/common/wireguard/Cargo.toml @@ -23,7 +23,7 @@ x25519-dalek = { workspace = true } ip_network = { workspace = true } log.workspace = true nym-crypto = { path = "../crypto", features = ["asymmetric"] } -nym-gateway-storage = { path = "../gateway-storage", features = ["wireguard"] } +nym-gateway-storage = { path = "../gateway-storage" } nym-network-defaults = { path = "../network-defaults" } nym-task = { path = "../task" } nym-wireguard-types = { path = "../wireguard-types" } diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index e5f43bc54d..4a62c70bee 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -93,10 +93,10 @@ nym-types = { path = "../common/types" } nym-validator-client = { path = "../common/client-libs/validator-client" } nym-ip-packet-router = { path = "../service-providers/ip-packet-router" } -nym-wireguard = { path = "../common/wireguard", optional = true } +nym-wireguard = { path = "../common/wireguard" } nym-wireguard-types = { path = "../common/wireguard-types", default-features = false } -defguard_wireguard_rs = { workspace = true, optional = true } +defguard_wireguard_rs = { workspace = true } [build-dependencies] @@ -109,11 +109,6 @@ sqlx = { workspace = true, features = [ ] } [features] -wireguard = [ - "nym-wireguard", - "defguard_wireguard_rs", - "nym-gateway-storage/wireguard", -] bin-deps = ["clap", 'nym-bin-common/output_format'] [package.metadata.deb] diff --git a/gateway/src/error.rs b/gateway/src/error.rs index 8dc005a0a1..4d9f8fc9b4 100644 --- a/gateway/src/error.rs +++ b/gateway/src/error.rs @@ -199,13 +199,11 @@ pub enum GatewayError { #[error("the current multisig contract is not using 'AbsolutePercentage' threshold!")] InvalidMultisigThreshold, - #[cfg(all(feature = "wireguard", target_os = "linux"))] #[error("failed to remove wireguard interface: {0}")] WireguardInterfaceError(#[from] defguard_wireguard_rs::error::WireguardInterfaceError), - #[cfg(all(feature = "wireguard", target_os = "linux"))] - #[error("wireguard not set")] - WireguardNotSet, + #[error("internal wireguard error {0}")] + InternalWireguardError(String), #[error("failed to start authenticator: {source}")] AuthenticatorStartError { diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 5de29f806a..47d3630b30 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -50,7 +50,6 @@ struct StartedNetworkRequester { // TODO: should this struct live here? #[allow(unused)] struct StartedAuthenticator { - #[cfg(feature = "wireguard")] wg_api: Arc, /// Handle to interact with the local authenticator @@ -145,7 +144,6 @@ pub struct Gateway { storage: St, - #[cfg(all(feature = "wireguard", target_os = "linux"))] wireguard_data: Option, run_http_server: bool, @@ -168,7 +166,6 @@ impl Gateway { network_requester_opts, ip_packet_router_opts, authenticator_opts: None, - #[cfg(all(feature = "wireguard", target_os = "linux"))] wireguard_data: None, run_http_server: true, task_client: None, @@ -192,7 +189,6 @@ impl Gateway { identity_keypair, sphinx_keypair, storage, - #[cfg(all(feature = "wireguard", target_os = "linux"))] wireguard_data: None, run_http_server: true, task_client: None, @@ -207,7 +203,6 @@ impl Gateway { self.task_client = Some(task_client) } - #[cfg(all(feature = "wireguard", target_os = "linux"))] pub fn set_wireguard_data(&mut self, wireguard_data: nym_wireguard::WireguardData) { self.wireguard_data = Some(wireguard_data) } @@ -245,7 +240,7 @@ impl Gateway { mixnet_handling::Listener::new(listening_address, shutdown).start(connection_handler); } - #[cfg(all(feature = "wireguard", target_os = "linux"))] + #[cfg(target_os = "linux")] async fn start_authenticator( &mut self, forwarding_channel: MixForwardingSender, @@ -317,11 +312,13 @@ impl Gateway { handle: LocalEmbeddedClientHandle::new(start_data.address, auth_mix_sender), }) } else { - Err(Box::new(GatewayError::WireguardNotSet)) + Err(Box::new(GatewayError::InternalWireguardError( + "wireguard not set".to_string(), + ))) } } - #[cfg(all(feature = "wireguard", not(target_os = "linux")))] + #[cfg(not(target_os = "linux"))] async fn start_authenticator( &self, _forwarding_channel: MixForwardingSender, @@ -654,14 +651,15 @@ impl Gateway { info!("embedded ip packet router is disabled"); }; - #[cfg(feature = "wireguard")] - let _wg_api = { + let _wg_api = if self.wireguard_data.is_some() { let embedded_auth = self .start_authenticator(mix_forwarding_channel, shutdown.fork("authenticator")) .await .map_err(|source| GatewayError::AuthenticatorStartError { source })?; active_clients_store.insert_embedded(embedded_auth.handle); Some(embedded_auth.wg_api) + } else { + None }; if self.run_http_server { diff --git a/nym-node/Cargo.toml b/nym-node/Cargo.toml index 942de6a37c..f33229d4bb 100644 --- a/nym-node/Cargo.toml +++ b/nym-node/Cargo.toml @@ -17,7 +17,7 @@ license = "GPL-3.0" anyhow.workspace = true bip39 = { workspace = true, features = ["zeroize"] } bs58.workspace = true -celes = { workspace = true } # country codes +celes = { workspace = true } # country codes colored = { workspace = true } clap = { workspace = true, features = ["cargo", "env"] } humantime-serde = { workspace = true } @@ -39,7 +39,10 @@ semver = { workspace = true } cupid = { workspace = true } sysinfo = { workspace = true } -nym-bin-common = { path = "../common/bin-common", features = ["basic_tracing", "output_format"] } +nym-bin-common = { path = "../common/bin-common", features = [ + "basic_tracing", + "output_format", +] } nym-client-core-config-types = { path = "../common/client-core/config-types" } nym-config = { path = "../common/config" } nym-crypto = { path = "../common/crypto", features = ["asymmetric", "rand"] } @@ -62,6 +65,3 @@ nym-ip-packet-router = { path = "../service-providers/ip-packet-router" } [build-dependencies] # temporary bonding information v1 (to grab and parse nym-mixnode and nym-gateway package versions) cargo_metadata = { workspace = true } - -[features] -wireguard = ["nym-gateway/wireguard"] diff --git a/nym-node/src/node/mod.rs b/nym-node/src/node/mod.rs index 19242eda04..d0361b5057 100644 --- a/nym-node/src/node/mod.rs +++ b/nym-node/src/node/mod.rs @@ -580,8 +580,9 @@ impl NymNode { ); entry_gateway.disable_http_server(); entry_gateway.set_task_client(task_client); - #[cfg(all(feature = "wireguard", target_os = "linux"))] - entry_gateway.set_wireguard_data(self.wireguard.into()); + if self.config.wireguard.enabled { + entry_gateway.set_wireguard_data(self.wireguard.into()); + } tokio::spawn(async move { if let Err(err) = entry_gateway.run().await { @@ -608,8 +609,9 @@ impl NymNode { ); exit_gateway.disable_http_server(); exit_gateway.set_task_client(task_client); - #[cfg(all(feature = "wireguard", target_os = "linux"))] - exit_gateway.set_wireguard_data(self.wireguard.into()); + if self.config.wireguard.enabled { + exit_gateway.set_wireguard_data(self.wireguard.into()); + } tokio::spawn(async move { if let Err(err) = exit_gateway.run().await { From 858b6c6094b76e576da13924a5aa3b2ffdea380f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 3 Sep 2024 14:26:57 +0100 Subject: [PATCH 25/41] restored (and deprecated) 'owner' field in ContractState --- .../mixnet-contract/src/types.rs | 6 ++++ contracts/mixnet/src/contract.rs | 7 ++++ .../src/mixnet_contract_settings/queries.rs | 2 ++ .../mixnet_contract_settings/transactions.rs | 16 +++++++-- contracts/mixnet/src/queued_migrations.rs | 35 +++++-------------- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs index e513a392c1..749de1cc7e 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs @@ -186,6 +186,12 @@ impl Index for LayerDistribution { /// The current state of the mixnet contract. #[cw_serde] pub struct ContractState { + /// Address of the contract owner. + #[deprecated( + note = "use explicit ADMIN instead. this field will be removed in future release" + )] + pub owner: Addr, + /// Address of "rewarding validator" (nym-api) that's allowed to send any rewarding-related transactions. pub rewarding_validator_address: Addr, diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index b9fe131e6d..5e7cacccd7 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -21,13 +21,17 @@ const CONTRACT_NAME: &str = "crate:nym-mixnet-contract"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); fn default_initial_state( + owner: Addr, rewarding_validator_address: Addr, rewarding_denom: String, vesting_contract_address: Addr, profit_margin: ProfitMarginRange, interval_operating_cost: OperatingCostRange, ) -> ContractState { + // we have to temporarily preserve this functionalities until it can be removed + #[allow(deprecated)] ContractState { + owner, rewarding_validator_address, vesting_contract_address, rewarding_denom: rewarding_denom.clone(), @@ -70,6 +74,7 @@ pub fn instantiate( let rewarding_validator_address = deps.api.addr_validate(&msg.rewarding_validator_address)?; let vesting_contract_address = deps.api.addr_validate(&msg.vesting_contract_address)?; let state = default_initial_state( + info.sender.clone(), rewarding_validator_address.clone(), msg.rewarding_denom, vesting_contract_address, @@ -600,7 +605,9 @@ mod tests { let res = instantiate(deps.as_mut(), env, sender, init_msg); assert!(res.is_ok()); + #[allow(deprecated)] let expected_state = ContractState { + owner: Addr::unchecked("sender"), rewarding_validator_address: Addr::unchecked("foomp123"), vesting_contract_address: Addr::unchecked("bar456"), rewarding_denom: "uatom".into(), diff --git a/contracts/mixnet/src/mixnet_contract_settings/queries.rs b/contracts/mixnet/src/mixnet_contract_settings/queries.rs index cfcda13e48..d8844c3adb 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/queries.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/queries.rs @@ -42,7 +42,9 @@ pub(crate) mod tests { fn query_for_contract_settings_works() { let mut deps = test_helpers::init_contract(); + #[allow(deprecated)] let dummy_state = ContractState { + owner: Addr::unchecked("foomp"), rewarding_validator_address: Addr::unchecked("monitor"), vesting_contract_address: Addr::unchecked("foomp"), rewarding_denom: "unym".to_string(), diff --git a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs index fc6a9ce30e..00da2ae97a 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs @@ -3,9 +3,9 @@ use super::storage; use crate::mixnet_contract_settings::storage::ADMIN; -use cosmwasm_std::DepsMut; use cosmwasm_std::MessageInfo; use cosmwasm_std::Response; +use cosmwasm_std::{DepsMut, StdResult}; use mixnet_contract_common::error::MixnetContractError; use mixnet_contract_common::events::{ new_rewarding_validator_address_update_event, new_settings_update_event, @@ -13,13 +13,23 @@ use mixnet_contract_common::events::{ use mixnet_contract_common::ContractStateParams; pub fn try_update_contract_admin( - deps: DepsMut<'_>, + mut deps: DepsMut<'_>, info: MessageInfo, new_admin: String, ) -> Result { let new_admin = deps.api.addr_validate(&new_admin)?; - Ok(ADMIN.execute_update_admin(deps, info, Some(new_admin))?) + let res = ADMIN.execute_update_admin(deps.branch(), info, Some(new_admin.clone()))?; + + // SAFETY: we don't need to perform any authentication checks on the sender as it was performed + // during 'execute_update_admin' call + #[allow(deprecated)] + storage::CONTRACT_STATE.update(deps.storage, |mut state| -> StdResult<_> { + state.owner = new_admin; + Ok(state) + })?; + + Ok(res) } pub fn try_update_rewarding_validator_address( diff --git a/contracts/mixnet/src/queued_migrations.rs b/contracts/mixnet/src/queued_migrations.rs index a6979d8c5c..68ee265f3b 100644 --- a/contracts/mixnet/src/queued_migrations.rs +++ b/contracts/mixnet/src/queued_migrations.rs @@ -1,14 +1,11 @@ // Copyright 2022-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::constants::CONTRACT_STATE_KEY; use crate::interval::storage as interval_storage; use crate::mixnet_contract_settings::storage as mixnet_params_storage; -use cosmwasm_std::{Addr, DepsMut, Order, Storage}; -use cw_storage_plus::Item; +use cosmwasm_std::{DepsMut, Order, Storage}; use mixnet_contract_common::error::MixnetContractError; -use mixnet_contract_common::{ContractState, ContractStateParams, PendingEpochEventKind}; -use serde::{Deserialize, Serialize}; +use mixnet_contract_common::PendingEpochEventKind; fn ensure_no_pending_proxy_events(storage: &dyn Storage) -> Result<(), MixnetContractError> { let last_executed = interval_storage::LAST_PROCESSED_EPOCH_EVENT.load(storage)?; @@ -55,27 +52,11 @@ pub(crate) fn vesting_purge(deps: DepsMut) -> Result<(), MixnetContractError> { } pub(crate) fn explicit_contract_admin(deps: DepsMut) -> Result<(), MixnetContractError> { - #[derive(Deserialize, Serialize)] - pub struct OldContractState { - pub owner: Addr, - pub rewarding_validator_address: Addr, - pub vesting_contract_address: Addr, - pub rewarding_denom: String, - pub params: ContractStateParams, - } - - let old_state_storage = Item::::new(CONTRACT_STATE_KEY); - let old_state = old_state_storage.load(deps.storage)?; - - mixnet_params_storage::initialise_storage( - deps, - ContractState { - rewarding_validator_address: old_state.rewarding_validator_address, - vesting_contract_address: old_state.vesting_contract_address, - rewarding_denom: old_state.rewarding_denom, - params: old_state.params, - }, - old_state.owner, - )?; + // we need to read the deprecated field to migrate it over + #[allow(deprecated)] + let existing_admin = mixnet_params_storage::CONTRACT_STATE + .load(deps.storage)? + .owner; + mixnet_params_storage::ADMIN.set(deps, Some(existing_admin))?; Ok(()) } From e76c8e06be1b2d0176e857987e742216a4d3ddc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 3 Sep 2024 16:35:42 +0100 Subject: [PATCH 26/41] updated contract schema --- .../mixnet/schema/nym-mixnet-contract.json | 51 +++++++++++++++++++ contracts/mixnet/schema/raw/execute.json | 22 ++++++++ contracts/mixnet/schema/raw/query.json | 13 +++++ .../mixnet/schema/raw/response_to_admin.json | 15 ++++++ .../schema/raw/response_to_get_state.json | 1 + 5 files changed, 102 insertions(+) create mode 100644 contracts/mixnet/schema/raw/response_to_admin.json diff --git a/contracts/mixnet/schema/nym-mixnet-contract.json b/contracts/mixnet/schema/nym-mixnet-contract.json index dc3e521bd2..772b9b6068 100644 --- a/contracts/mixnet/schema/nym-mixnet-contract.json +++ b/contracts/mixnet/schema/nym-mixnet-contract.json @@ -177,6 +177,28 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "ExecuteMsg", "oneOf": [ + { + "description": "Change the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -1692,6 +1714,19 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "QueryMsg", "oneOf": [ + { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Gets the list of families registered in this contract.", "type": "object", @@ -2937,6 +2972,21 @@ }, "sudo": null, "responses": { + "admin": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AdminResponse", + "description": "Returned from Admin.query_admin()", + "type": "object", + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, "get_all_delegations": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "PagedAllDelegationsResponse", @@ -8149,6 +8199,7 @@ "properties": { "owner": { "description": "Address of the contract owner.", + "deprecated": true, "allOf": [ { "$ref": "#/definitions/Addr" diff --git a/contracts/mixnet/schema/raw/execute.json b/contracts/mixnet/schema/raw/execute.json index 688b57db0b..c5c773e76d 100644 --- a/contracts/mixnet/schema/raw/execute.json +++ b/contracts/mixnet/schema/raw/execute.json @@ -2,6 +2,28 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "ExecuteMsg", "oneOf": [ + { + "description": "Change the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ diff --git a/contracts/mixnet/schema/raw/query.json b/contracts/mixnet/schema/raw/query.json index f4738a91fe..c938a56f64 100644 --- a/contracts/mixnet/schema/raw/query.json +++ b/contracts/mixnet/schema/raw/query.json @@ -2,6 +2,19 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "QueryMsg", "oneOf": [ + { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Gets the list of families registered in this contract.", "type": "object", diff --git a/contracts/mixnet/schema/raw/response_to_admin.json b/contracts/mixnet/schema/raw/response_to_admin.json new file mode 100644 index 0000000000..c73969ab04 --- /dev/null +++ b/contracts/mixnet/schema/raw/response_to_admin.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AdminResponse", + "description": "Returned from Admin.query_admin()", + "type": "object", + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false +} diff --git a/contracts/mixnet/schema/raw/response_to_get_state.json b/contracts/mixnet/schema/raw/response_to_get_state.json index d8c9dc5383..616f678dbd 100644 --- a/contracts/mixnet/schema/raw/response_to_get_state.json +++ b/contracts/mixnet/schema/raw/response_to_get_state.json @@ -13,6 +13,7 @@ "properties": { "owner": { "description": "Address of the contract owner.", + "deprecated": true, "allOf": [ { "$ref": "#/definitions/Addr" From ed7a84a1cebc97821290e2b9c9c760906b4232fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 4 Sep 2024 09:55:23 +0100 Subject: [PATCH 27/41] made 'owner' field optional to prepare for its future removal --- .../cosmwasm-smart-contracts/mixnet-contract/src/types.rs | 3 ++- contracts/mixnet/schema/nym-mixnet-contract.json | 7 +++++-- contracts/mixnet/schema/raw/response_to_get_state.json | 7 +++++-- contracts/mixnet/src/contract.rs | 4 ++-- contracts/mixnet/src/mixnet_contract_settings/queries.rs | 2 +- .../mixnet/src/mixnet_contract_settings/transactions.rs | 2 +- contracts/mixnet/src/queued_migrations.rs | 6 +++++- 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs index 749de1cc7e..f95c15eb34 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs @@ -190,7 +190,8 @@ pub struct ContractState { #[deprecated( note = "use explicit ADMIN instead. this field will be removed in future release" )] - pub owner: Addr, + #[serde(default)] + pub owner: Option, /// Address of "rewarding validator" (nym-api) that's allowed to send any rewarding-related transactions. pub rewarding_validator_address: Addr, diff --git a/contracts/mixnet/schema/nym-mixnet-contract.json b/contracts/mixnet/schema/nym-mixnet-contract.json index 772b9b6068..c754e65fdb 100644 --- a/contracts/mixnet/schema/nym-mixnet-contract.json +++ b/contracts/mixnet/schema/nym-mixnet-contract.json @@ -8190,7 +8190,6 @@ "description": "The current state of the mixnet contract.", "type": "object", "required": [ - "owner", "params", "rewarding_denom", "rewarding_validator_address", @@ -8199,10 +8198,14 @@ "properties": { "owner": { "description": "Address of the contract owner.", + "default": null, "deprecated": true, - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/Addr" + }, + { + "type": "null" } ] }, diff --git a/contracts/mixnet/schema/raw/response_to_get_state.json b/contracts/mixnet/schema/raw/response_to_get_state.json index 616f678dbd..9103e87b72 100644 --- a/contracts/mixnet/schema/raw/response_to_get_state.json +++ b/contracts/mixnet/schema/raw/response_to_get_state.json @@ -4,7 +4,6 @@ "description": "The current state of the mixnet contract.", "type": "object", "required": [ - "owner", "params", "rewarding_denom", "rewarding_validator_address", @@ -13,10 +12,14 @@ "properties": { "owner": { "description": "Address of the contract owner.", + "default": null, "deprecated": true, - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/Addr" + }, + { + "type": "null" } ] }, diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 5e7cacccd7..f56af17cd7 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -31,7 +31,7 @@ fn default_initial_state( // we have to temporarily preserve this functionalities until it can be removed #[allow(deprecated)] ContractState { - owner, + owner: Some(owner), rewarding_validator_address, vesting_contract_address, rewarding_denom: rewarding_denom.clone(), @@ -607,7 +607,7 @@ mod tests { #[allow(deprecated)] let expected_state = ContractState { - owner: Addr::unchecked("sender"), + owner: Some(Addr::unchecked("sender")), rewarding_validator_address: Addr::unchecked("foomp123"), vesting_contract_address: Addr::unchecked("bar456"), rewarding_denom: "uatom".into(), diff --git a/contracts/mixnet/src/mixnet_contract_settings/queries.rs b/contracts/mixnet/src/mixnet_contract_settings/queries.rs index d8844c3adb..5d80fec78a 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/queries.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/queries.rs @@ -44,7 +44,7 @@ pub(crate) mod tests { #[allow(deprecated)] let dummy_state = ContractState { - owner: Addr::unchecked("foomp"), + owner: Some(Addr::unchecked("foomp")), rewarding_validator_address: Addr::unchecked("monitor"), vesting_contract_address: Addr::unchecked("foomp"), rewarding_denom: "unym".to_string(), diff --git a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs index 00da2ae97a..b458f6fbbc 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs @@ -25,7 +25,7 @@ pub fn try_update_contract_admin( // during 'execute_update_admin' call #[allow(deprecated)] storage::CONTRACT_STATE.update(deps.storage, |mut state| -> StdResult<_> { - state.owner = new_admin; + state.owner = Some(new_admin); Ok(state) })?; diff --git a/contracts/mixnet/src/queued_migrations.rs b/contracts/mixnet/src/queued_migrations.rs index 68ee265f3b..248a33d30e 100644 --- a/contracts/mixnet/src/queued_migrations.rs +++ b/contracts/mixnet/src/queued_migrations.rs @@ -54,9 +54,13 @@ pub(crate) fn vesting_purge(deps: DepsMut) -> Result<(), MixnetContractError> { pub(crate) fn explicit_contract_admin(deps: DepsMut) -> Result<(), MixnetContractError> { // we need to read the deprecated field to migrate it over #[allow(deprecated)] + // SAFETY: this value should ALWAYS exist on the first execution of this migration; + // as a matter of fact, it should ALWAYS continue existing until another migration + #[allow(clippy::expect_used)] let existing_admin = mixnet_params_storage::CONTRACT_STATE .load(deps.storage)? - .owner; + .owner + .expect("the contract state is corrupt - there's no admin set"); mixnet_params_storage::ADMIN.set(deps, Some(existing_admin))?; Ok(()) } From babc84779ca1534f9e4592994d2cab07c3807302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 9 Sep 2024 16:19:04 +0200 Subject: [PATCH 28/41] Backport 4844 and 4845 --- common/ip-packet-requests/src/v7/request.rs | 4 +++- nym-wallet/src-tauri/src/operations/signatures/sign.rs | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/common/ip-packet-requests/src/v7/request.rs b/common/ip-packet-requests/src/v7/request.rs index 24f9819c2a..73266320e3 100644 --- a/common/ip-packet-requests/src/v7/request.rs +++ b/common/ip-packet-requests/src/v7/request.rs @@ -415,6 +415,8 @@ pub struct HealthRequest { #[cfg(test)] mod tests { + use time::macros::datetime; + use super::*; use std::net::{Ipv4Addr, Ipv6Addr}; use std::str::FromStr; @@ -432,7 +434,7 @@ mod tests { reply_to_hops: None, reply_to_avg_mix_delays: None, buffer_timeout: None, - timestamp: OffsetDateTime::now_utc(), + timestamp: datetime!(2024-01-01 12:59:59.5 UTC), }, signature: None, } diff --git a/nym-wallet/src-tauri/src/operations/signatures/sign.rs b/nym-wallet/src-tauri/src/operations/signatures/sign.rs index c494bc5b4f..59da5cae36 100644 --- a/nym-wallet/src-tauri/src/operations/signatures/sign.rs +++ b/nym-wallet/src-tauri/src/operations/signatures/sign.rs @@ -131,8 +131,5 @@ pub async fn verify( let message_as_bytes = message.into_bytes(); Ok(verifying_key .verify(&message_as_bytes, &signature) - .map_err(|e| { - log::error!(">>> Verification failed, wrong signature"); - e - })?) + .inspect_err(|_| log::error!(">>> Verification failed, wrong signature"))?) } From 74252269bc18f87226bbfba959e60c0df3089cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 9 Sep 2024 14:35:29 +0100 Subject: [PATCH 29/41] utility to convert private keys into keypairs --- common/crypto/src/asymmetric/encryption/mod.rs | 9 +++++++++ common/crypto/src/asymmetric/identity/mod.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/common/crypto/src/asymmetric/encryption/mod.rs b/common/crypto/src/asymmetric/encryption/mod.rs index cadb5437e4..75ea0b2206 100644 --- a/common/crypto/src/asymmetric/encryption/mod.rs +++ b/common/crypto/src/asymmetric/encryption/mod.rs @@ -81,6 +81,15 @@ impl KeyPair { } } +impl From for KeyPair { + fn from(private_key: PrivateKey) -> Self { + KeyPair { + public_key: (&private_key).into(), + private_key, + } + } +} + impl PemStorableKeyPair for KeyPair { type PrivatePemKey = PrivateKey; type PublicPemKey = PublicKey; diff --git a/common/crypto/src/asymmetric/identity/mod.rs b/common/crypto/src/asymmetric/identity/mod.rs index f65290f907..41afaf67a4 100644 --- a/common/crypto/src/asymmetric/identity/mod.rs +++ b/common/crypto/src/asymmetric/identity/mod.rs @@ -91,6 +91,15 @@ impl KeyPair { } } +impl From for KeyPair { + fn from(private_key: PrivateKey) -> Self { + KeyPair { + public_key: (&private_key).into(), + private_key, + } + } +} + impl PemStorableKeyPair for KeyPair { type PrivatePemKey = PrivateKey; type PublicPemKey = PublicKey; From 1162de3673ed70d4d3abc27470491d085720b1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 9 Sep 2024 14:35:38 +0100 Subject: [PATCH 30/41] additional logs --- .../websocket/connection_handler/fresh.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs b/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs index fc5f453e25..cccaf71dff 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs @@ -529,6 +529,11 @@ where /// * `client_address`: address of the client wishing to authenticate. /// * `encrypted_address`: ciphertext of the address of the client wishing to authenticate. /// * `iv`: fresh IV received with the request. + #[instrument(skip_all + fields( + address = %address, + ) + )] async fn handle_authenticate( &mut self, client_protocol_version: Option, @@ -539,6 +544,8 @@ where where S: AsyncRead + AsyncWrite + Unpin, { + debug!("handling client registration"); + let negotiated_protocol = self.negotiate_client_protocol(client_protocol_version)?; // populate the negotiated protocol for future uses self.negotiated_protocol = Some(negotiated_protocol); @@ -662,6 +669,8 @@ where let remote_identity = Self::extract_remote_identity_from_register_init(&init_data)?; let remote_address = remote_identity.derive_destination_address(); + debug!(remote_client = %remote_identity); + if self.active_clients_store.is_active(remote_address) { return Err(InitialAuthenticationError::DuplicateConnection); } @@ -669,6 +678,8 @@ where let shared_keys = self.perform_registration_handshake(init_data).await?; let client_id = self.register_client(remote_address, &shared_keys).await?; + debug!(client_id = %client_id, "managed to finalize client registration"); + let client_details = ClientDetails::new(client_id, remote_address, shared_keys); Ok(InitialAuthResult::new( From c023c8fb9f7b2536c76ca481a10c861d1420d493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 9 Sep 2024 14:35:59 +0100 Subject: [PATCH 31/41] updating shared keys without deleting the row --- common/gateway-storage/src/shared_keys.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/gateway-storage/src/shared_keys.rs b/common/gateway-storage/src/shared_keys.rs index 8d16ca5ba5..97171eab85 100644 --- a/common/gateway-storage/src/shared_keys.rs +++ b/common/gateway-storage/src/shared_keys.rs @@ -40,9 +40,17 @@ impl SharedKeysManager { client_address_bs58: String, derived_aes128_ctr_blake3_hmac_keys_bs58: String, ) -> Result { - sqlx::query!("INSERT OR REPLACE INTO shared_keys(client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58) VALUES (?, ?)", + // https://stackoverflow.com/a/20310838 + // we don't want to be using `INSERT OR REPLACE INTO` due to the foreign key on `available_bandwidth` if the entry already exists + sqlx::query!( + r#" + INSERT OR IGNORE INTO shared_keys(client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58) VALUES (?, ?); + UPDATE shared_keys SET derived_aes128_ctr_blake3_hmac_keys_bs58 = ? WHERE client_address_bs58 = ? + "#, client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, + derived_aes128_ctr_blake3_hmac_keys_bs58, + client_address_bs58, ).execute(&self.connection_pool).await?; self.client_id(&client_address_bs58).await From c3aec2b01f4890eb12686f930ed70300c79a4728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 9 Sep 2024 15:09:55 +0100 Subject: [PATCH 32/41] update wireguard peers without replacing rows --- common/gateway-storage/src/wireguard_peers.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/common/gateway-storage/src/wireguard_peers.rs b/common/gateway-storage/src/wireguard_peers.rs index 436cdc3475..c90eb9647d 100644 --- a/common/gateway-storage/src/wireguard_peers.rs +++ b/common/gateway-storage/src/wireguard_peers.rs @@ -26,8 +26,17 @@ impl WgPeerManager { /// * `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 + r#" + INSERT OR IGNORE INTO wireguard_peer(public_key, preshared_key, protocol_version, endpoint, last_handshake, tx_bytes, rx_bytes, persistent_keepalive_interval, allowed_ips, suspended) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + UPDATE wireguard_peer + SET preshared_key = ?, protocol_version = ?, endpoint = ?, last_handshake = ?, tx_bytes = ?, rx_bytes = ?, persistent_keepalive_interval = ?, allowed_ips = ?, suspended = ? + WHERE public_key = ? + "#, + 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, + + 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,peer.public_key, ) .execute(&self.connection_pool) .await?; From 61eaffe91badc4f47b992c0261e5159b7966eb50 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 10 Sep 2024 09:49:52 +0200 Subject: [PATCH 33/41] update changelog --- CHANGELOG.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e685c9e46..fbed61bd54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,19 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// ## [Unreleased] -## [2024.10-caramello] (2024-08-19) +## [2024.10-caramello] (2024-09-10) +- Backport 4844 and 4845 ([#4857]) +- Bugfix/client registration vol2 ([#4856]) +- Remove wireguard feature flag and pass runtime enabled flag ([#4839]) +- Eliminate cancel unsafe sig awaiting ([#4834]) +- added explicit updateable admin to the mixnet contract ([#4822]) +- using legacy signing payload in CLI and verifying both variants in contract ([#4821]) +- adding ecash contract address ([#4819]) +- Check profit margin of node before defaulting to hardcoded value ([#4802]) +- Sync last_seen_bandwidth immediately ([#4774]) +- Feature/additional ecash nym cli utils ([#4773]) +- Better storage error logging ([#4772]) - 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]) @@ -21,6 +32,17 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// - Fix (some) feature unification build failures ([#4681]) - Feature Compact Ecash : The One PR ([#4623]) +[#4857]: https://github.com/nymtech/nym/pull/4857 +[#4856]: https://github.com/nymtech/nym/pull/4856 +[#4839]: https://github.com/nymtech/nym/pull/4839 +[#4834]: https://github.com/nymtech/nym/pull/4834 +[#4822]: https://github.com/nymtech/nym/pull/4822 +[#4821]: https://github.com/nymtech/nym/pull/4821 +[#4819]: https://github.com/nymtech/nym/pull/4819 +[#4802]: https://github.com/nymtech/nym/pull/4802 +[#4774]: https://github.com/nymtech/nym/pull/4774 +[#4773]: https://github.com/nymtech/nym/pull/4773 +[#4772]: https://github.com/nymtech/nym/pull/4772 [#4764]: https://github.com/nymtech/nym/pull/4764 [#4746]: https://github.com/nymtech/nym/pull/4746 [#4742]: https://github.com/nymtech/nym/pull/4742 From 48dfc24c33e3d0a70ec6fcc819f391f26a481e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 10 Sep 2024 10:23:02 +0200 Subject: [PATCH 34/41] Update upload-artifact action to v4 --- .github/workflows/ci-build-upload-binaries.yml | 2 +- .github/workflows/nightly-security-audit.yml | 2 +- .github/workflows/publish-nym-binaries.yml | 2 +- .github/workflows/publish-nym-contracts.yml | 4 ++-- .github/workflows/publish-nym-wallet-macos.yml | 2 +- .github/workflows/publish-nym-wallet-ubuntu.yml | 2 +- .github/workflows/publish-nym-wallet-win10.yml | 2 +- .github/workflows/publish-nyms5-android-apk.yml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-build-upload-binaries.yml b/.github/workflows/ci-build-upload-binaries.yml index cd0067e7d4..96352f5705 100644 --- a/.github/workflows/ci-build-upload-binaries.yml +++ b/.github/workflows/ci-build-upload-binaries.yml @@ -87,7 +87,7 @@ jobs: - name: Upload Artifact if: github.event_name == 'workflow_dispatch' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: nym-binaries-artifacts path: | diff --git a/.github/workflows/nightly-security-audit.yml b/.github/workflows/nightly-security-audit.yml index 808cc20144..9ab16f9eba 100644 --- a/.github/workflows/nightly-security-audit.yml +++ b/.github/workflows/nightly-security-audit.yml @@ -20,7 +20,7 @@ jobs: find . -name Cargo.toml -exec cargo deny --manifest-path {} check \ advisories -A advisory-not-detected --hide-inclusion-graph \; &> \ >(uniq &> .github/workflows/support-files/notifications/deny.message ) - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@@v4 with: name: report path: .github/workflows/support-files/notifications/deny.message diff --git a/.github/workflows/publish-nym-binaries.yml b/.github/workflows/publish-nym-binaries.yml index 32cc171ac2..a8e0bc976b 100644 --- a/.github/workflows/publish-nym-binaries.yml +++ b/.github/workflows/publish-nym-binaries.yml @@ -63,7 +63,7 @@ jobs: args: --workspace --release ${{ env.CARGO_FEATURES }} - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: my-artifact path: | diff --git a/.github/workflows/publish-nym-contracts.yml b/.github/workflows/publish-nym-contracts.yml index 493f99e8ac..781f012fcb 100644 --- a/.github/workflows/publish-nym-contracts.yml +++ b/.github/workflows/publish-nym-contracts.yml @@ -26,14 +26,14 @@ jobs: run: make contracts - name: Upload Mixnet Contract Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: mixnet_contract.wasm path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm retention-days: 5 - name: Upload Vesting Contract Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: vesting_contract.wasm path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm diff --git a/.github/workflows/publish-nym-wallet-macos.yml b/.github/workflows/publish-nym-wallet-macos.yml index 4ecc48d276..d7baecc6a3 100644 --- a/.github/workflows/publish-nym-wallet-macos.yml +++ b/.github/workflows/publish-nym-wallet-macos.yml @@ -83,7 +83,7 @@ jobs: run: yarn && yarn build - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: nym-wallet.app.tar.gz path: nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz diff --git a/.github/workflows/publish-nym-wallet-ubuntu.yml b/.github/workflows/publish-nym-wallet-ubuntu.yml index 1eaad9bef0..2fd9273751 100644 --- a/.github/workflows/publish-nym-wallet-ubuntu.yml +++ b/.github/workflows/publish-nym-wallet-ubuntu.yml @@ -62,7 +62,7 @@ jobs: TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: nym-wallet_1.0.0_amd64.AppImage.tar.gz path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz diff --git a/.github/workflows/publish-nym-wallet-win10.yml b/.github/workflows/publish-nym-wallet-win10.yml index 5bba585f18..e99db0f24b 100644 --- a/.github/workflows/publish-nym-wallet-win10.yml +++ b/.github/workflows/publish-nym-wallet-win10.yml @@ -82,7 +82,7 @@ jobs: run: yarn build - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: nym-wallet_1.0.0_x64_en-US.msi path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi diff --git a/.github/workflows/publish-nyms5-android-apk.yml b/.github/workflows/publish-nyms5-android-apk.yml index 06f4c6c126..599a8bf54d 100644 --- a/.github/workflows/publish-nyms5-android-apk.yml +++ b/.github/workflows/publish-nyms5-android-apk.yml @@ -84,7 +84,7 @@ jobs: apk/nyms5-arch64-release.apk - name: Upload APKs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@@v4 with: name: nyms5-apk-arch64 path: | From d6393c14969e9f1ce3381a814951335cd85e92ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 10 Sep 2024 10:23:36 +0200 Subject: [PATCH 35/41] Update download-artifact action to v4 --- .github/workflows/nightly-security-audit.yml | 2 +- .github/workflows/publish-nyms5-android-apk.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly-security-audit.yml b/.github/workflows/nightly-security-audit.yml index 9ab16f9eba..6f720403d3 100644 --- a/.github/workflows/nightly-security-audit.yml +++ b/.github/workflows/nightly-security-audit.yml @@ -31,7 +31,7 @@ jobs: - name: Check out repository code uses: actions/checkout@v2 - name: Download report from previous job - uses: actions/download-artifact@v3 + uses: actions/download-artifact@@v4 with: name: report path: .github/workflows/support-files/notifications diff --git a/.github/workflows/publish-nyms5-android-apk.yml b/.github/workflows/publish-nyms5-android-apk.yml index 599a8bf54d..56da06c9cc 100644 --- a/.github/workflows/publish-nyms5-android-apk.yml +++ b/.github/workflows/publish-nyms5-android-apk.yml @@ -99,7 +99,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Download binary artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@@v4 with: name: nyms5-apk-arch64 path: apk From eb98c1bf337255baaaee9f037405227f10607d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 10 Sep 2024 10:39:30 +0200 Subject: [PATCH 36/41] Fix incorrect sed search-replace --- .github/workflows/ci-build-upload-binaries.yml | 2 +- .github/workflows/nightly-security-audit.yml | 4 ++-- .github/workflows/publish-nym-binaries.yml | 2 +- .github/workflows/publish-nym-contracts.yml | 4 ++-- .github/workflows/publish-nym-wallet-macos.yml | 2 +- .github/workflows/publish-nym-wallet-ubuntu.yml | 2 +- .github/workflows/publish-nym-wallet-win10.yml | 2 +- .github/workflows/publish-nyms5-android-apk.yml | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-build-upload-binaries.yml b/.github/workflows/ci-build-upload-binaries.yml index 96352f5705..2a0f46f75e 100644 --- a/.github/workflows/ci-build-upload-binaries.yml +++ b/.github/workflows/ci-build-upload-binaries.yml @@ -87,7 +87,7 @@ jobs: - name: Upload Artifact if: github.event_name == 'workflow_dispatch' - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: nym-binaries-artifacts path: | diff --git a/.github/workflows/nightly-security-audit.yml b/.github/workflows/nightly-security-audit.yml index 6f720403d3..0addd5a6ce 100644 --- a/.github/workflows/nightly-security-audit.yml +++ b/.github/workflows/nightly-security-audit.yml @@ -20,7 +20,7 @@ jobs: find . -name Cargo.toml -exec cargo deny --manifest-path {} check \ advisories -A advisory-not-detected --hide-inclusion-graph \; &> \ >(uniq &> .github/workflows/support-files/notifications/deny.message ) - - uses: actions/upload-artifact@@v4 + - uses: actions/upload-artifact@v4 with: name: report path: .github/workflows/support-files/notifications/deny.message @@ -31,7 +31,7 @@ jobs: - name: Check out repository code uses: actions/checkout@v2 - name: Download report from previous job - uses: actions/download-artifact@@v4 + uses: actions/download-artifact@v4 with: name: report path: .github/workflows/support-files/notifications diff --git a/.github/workflows/publish-nym-binaries.yml b/.github/workflows/publish-nym-binaries.yml index a8e0bc976b..039598439a 100644 --- a/.github/workflows/publish-nym-binaries.yml +++ b/.github/workflows/publish-nym-binaries.yml @@ -63,7 +63,7 @@ jobs: args: --workspace --release ${{ env.CARGO_FEATURES }} - name: Upload Artifact - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: my-artifact path: | diff --git a/.github/workflows/publish-nym-contracts.yml b/.github/workflows/publish-nym-contracts.yml index 781f012fcb..189c906811 100644 --- a/.github/workflows/publish-nym-contracts.yml +++ b/.github/workflows/publish-nym-contracts.yml @@ -26,14 +26,14 @@ jobs: run: make contracts - name: Upload Mixnet Contract Artifact - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: mixnet_contract.wasm path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm retention-days: 5 - name: Upload Vesting Contract Artifact - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: vesting_contract.wasm path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm diff --git a/.github/workflows/publish-nym-wallet-macos.yml b/.github/workflows/publish-nym-wallet-macos.yml index d7baecc6a3..9357555d3b 100644 --- a/.github/workflows/publish-nym-wallet-macos.yml +++ b/.github/workflows/publish-nym-wallet-macos.yml @@ -83,7 +83,7 @@ jobs: run: yarn && yarn build - name: Upload Artifact - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: nym-wallet.app.tar.gz path: nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz diff --git a/.github/workflows/publish-nym-wallet-ubuntu.yml b/.github/workflows/publish-nym-wallet-ubuntu.yml index 2fd9273751..833bfaa745 100644 --- a/.github/workflows/publish-nym-wallet-ubuntu.yml +++ b/.github/workflows/publish-nym-wallet-ubuntu.yml @@ -62,7 +62,7 @@ jobs: TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - name: Upload Artifact - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: nym-wallet_1.0.0_amd64.AppImage.tar.gz path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz diff --git a/.github/workflows/publish-nym-wallet-win10.yml b/.github/workflows/publish-nym-wallet-win10.yml index e99db0f24b..ae0135b320 100644 --- a/.github/workflows/publish-nym-wallet-win10.yml +++ b/.github/workflows/publish-nym-wallet-win10.yml @@ -82,7 +82,7 @@ jobs: run: yarn build - name: Upload Artifact - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: nym-wallet_1.0.0_x64_en-US.msi path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi diff --git a/.github/workflows/publish-nyms5-android-apk.yml b/.github/workflows/publish-nyms5-android-apk.yml index 56da06c9cc..5df103cc0b 100644 --- a/.github/workflows/publish-nyms5-android-apk.yml +++ b/.github/workflows/publish-nyms5-android-apk.yml @@ -84,7 +84,7 @@ jobs: apk/nyms5-arch64-release.apk - name: Upload APKs - uses: actions/upload-artifact@@v4 + uses: actions/upload-artifact@v4 with: name: nyms5-apk-arch64 path: | @@ -99,7 +99,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Download binary artifact - uses: actions/download-artifact@@v4 + uses: actions/download-artifact@v4 with: name: nyms5-apk-arch64 path: apk From 58c74199d1e4c72c8f97321b01ae9e754b19e0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 10 Sep 2024 10:59:21 +0200 Subject: [PATCH 37/41] Fix upload-artifacts --- .github/workflows/release-calculate-hash.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-calculate-hash.yml b/.github/workflows/release-calculate-hash.yml index fb493b8541..94c764e6e0 100644 --- a/.github/workflows/release-calculate-hash.yml +++ b/.github/workflows/release-calculate-hash.yml @@ -30,7 +30,7 @@ jobs: with: release-tag-or-name-or-id: ${{ inputs.release_tag }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: Asset Hashes path: hashes.json From 01221a8e8c1a23c9eb25d95093771aa882f13e28 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 10 Sep 2024 13:51:11 +0200 Subject: [PATCH 38/41] bump wallet version --- nym-wallet/package.json | 2 +- nym-wallet/src-tauri/Cargo.toml | 2 +- nym-wallet/src-tauri/tauri.conf.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nym-wallet/package.json b/nym-wallet/package.json index e9098e8c15..3d97eefd26 100644 --- a/nym-wallet/package.json +++ b/nym-wallet/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/nym-wallet-app", - "version": "1.2.13", + "version": "1.2.14", "license": "MIT", "main": "index.js", "scripts": { diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index f3d463f188..8e995a784f 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym_wallet" -version = "1.2.13" +version = "1.2.14" description = "Nym Native Wallet" authors = ["Nym Technologies SA"] license = "" diff --git a/nym-wallet/src-tauri/tauri.conf.json b/nym-wallet/src-tauri/tauri.conf.json index 5236817066..0067868c37 100644 --- a/nym-wallet/src-tauri/tauri.conf.json +++ b/nym-wallet/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "nym-wallet", - "version": "1.2.13" + "version": "1.2.14" }, "build": { "distDir": "../dist", From 891fdeb4b5135f1075bb46d40d2fcb9cd5e167ef Mon Sep 17 00:00:00 2001 From: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:22:34 +0200 Subject: [PATCH 39/41] Update and rename publish-nym-wallet-win10.yml to publish-nym-wallet-win11.yml --- ...lish-nym-wallet-win10.yml => publish-nym-wallet-win11.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{publish-nym-wallet-win10.yml => publish-nym-wallet-win11.yml} (98%) diff --git a/.github/workflows/publish-nym-wallet-win10.yml b/.github/workflows/publish-nym-wallet-win11.yml similarity index 98% rename from .github/workflows/publish-nym-wallet-win10.yml rename to .github/workflows/publish-nym-wallet-win11.yml index ae0135b320..7ec8a2c02e 100644 --- a/.github/workflows/publish-nym-wallet-win10.yml +++ b/.github/workflows/publish-nym-wallet-win11.yml @@ -1,4 +1,4 @@ -name: publish-nym-wallet-win10 +name: publish-nym-wallet-win11 on: workflow_dispatch: release: @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - platform: [windows10] + platform: [windows11] runs-on: ${{ matrix.platform }} outputs: From f2d56882fe9cb659e84ee274b87b3a811e484afc Mon Sep 17 00:00:00 2001 From: Tommy Verrall Date: Tue, 10 Sep 2024 17:44:23 +0200 Subject: [PATCH 40/41] adding correct runner name --- .github/workflows/publish-nym-wallet-win11.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-nym-wallet-win11.yml b/.github/workflows/publish-nym-wallet-win11.yml index 7ec8a2c02e..ea3b301090 100644 --- a/.github/workflows/publish-nym-wallet-win11.yml +++ b/.github/workflows/publish-nym-wallet-win11.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - platform: [windows11] + platform: [custom-windows-11] runs-on: ${{ matrix.platform }} outputs: From 8c021e953719121f38326dabba65a6bf0ccebc55 Mon Sep 17 00:00:00 2001 From: Tommy Verrall Date: Tue, 10 Sep 2024 18:02:55 +0200 Subject: [PATCH 41/41] install yarn --- .github/workflows/publish-nym-wallet-win11.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish-nym-wallet-win11.yml b/.github/workflows/publish-nym-wallet-win11.yml index ea3b301090..312bcac6cf 100644 --- a/.github/workflows/publish-nym-wallet-win11.yml +++ b/.github/workflows/publish-nym-wallet-win11.yml @@ -62,6 +62,9 @@ jobs: fileName: '.env' encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} + - name: Install Yarn + run: npm install -g yarn + - name: Install project dependencies shell: bash run: cd .. && yarn --network-timeout 100000