Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 81e31c0550 | |||
| 1c771df941 | |||
| 17c2aecd99 | |||
| 85074f3ac8 | |||
| c7020da81c |
@@ -80,7 +80,7 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install --version 0.112.0 wasm-opt
|
||||
run: cargo install --version 0.110.0 wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install --version 0.112.0 wasm-opt
|
||||
run: cargo install --version 0.110.0 wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
+2
-12
@@ -4,19 +4,9 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.14] (2023-04-04)
|
||||
- nym-network-statistics properly handles signals ([#3209])
|
||||
|
||||
- Investigate cause of qwerty validator being in invalid rewarding state ([#3224])
|
||||
- Fix NR config due to changes in #3199 ([#3223])
|
||||
- [Issue] Mixnodes and gateway do not close connections properly ([#3187])
|
||||
- disable sign-ext when using wasm-opt + update wasm-opt ([#3203])
|
||||
- chore: tidy up client `Debug` config section ([#3199])
|
||||
|
||||
[#3224]: https://github.com/nymtech/nym/issues/3224
|
||||
[#3223]: https://github.com/nymtech/nym/issues/3223
|
||||
[#3187]: https://github.com/nymtech/nym/issues/3187
|
||||
[#3203]: https://github.com/nymtech/nym/pull/3203
|
||||
[#3199]: https://github.com/nymtech/nym/pull/3199
|
||||
[#3209]: https://github.com/nymtech/nym/issues/3209
|
||||
|
||||
## [v1.1.13] (2023-03-15)
|
||||
|
||||
|
||||
Generated
+12
-12
@@ -653,7 +653,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "client-core"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dashmap 5.4.0",
|
||||
@@ -1610,7 +1610,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.1.11",
|
||||
@@ -3059,7 +3059,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.15"
|
||||
version = "1.1.14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3139,7 +3139,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-bin-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"clap 4.1.11",
|
||||
"clap_complete",
|
||||
@@ -3168,7 +3168,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -3210,7 +3210,6 @@ dependencies = [
|
||||
"nym-coconut-bandwidth-contract-common",
|
||||
"nym-coconut-dkg-common",
|
||||
"nym-contracts-common",
|
||||
"nym-crypto",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-multisig-contract-common",
|
||||
"nym-network-defaults",
|
||||
@@ -3228,7 +3227,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"clap 4.1.11",
|
||||
"client-core",
|
||||
@@ -3403,7 +3402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3489,7 +3488,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.15"
|
||||
version = "1.1.14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
@@ -3558,7 +3557,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"clap 4.1.11",
|
||||
@@ -3596,12 +3595,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-statistics"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-statistics-common",
|
||||
"nym-task",
|
||||
"pretty_env_logger",
|
||||
"rocket",
|
||||
"serde",
|
||||
@@ -3696,7 +3696,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
dependencies = [
|
||||
"clap 4.1.11",
|
||||
"client-core",
|
||||
|
||||
@@ -81,8 +81,8 @@ build-nym-cli:
|
||||
|
||||
wasm:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
wasm-opt --disable-sign-ext -Os contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
||||
wasm-opt --disable-sign-ext -Os contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
||||
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
|
||||
# NOTE: this seems deprecated an not needed anymore?
|
||||
mixnet-opt: wasm
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client-core"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
|
||||
@@ -5,11 +5,7 @@ use crate::{client::replies::reply_storage, config::DebugConfig};
|
||||
|
||||
pub fn setup_empty_reply_surb_backend(debug_config: &DebugConfig) -> reply_storage::Empty {
|
||||
reply_storage::Empty {
|
||||
min_surb_threshold: debug_config
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,15 +236,15 @@ where
|
||||
|
||||
let mut stream = LoopCoverTrafficStream::new(
|
||||
ack_key,
|
||||
debug_config.acknowledgements.average_ack_delay,
|
||||
debug_config.traffic.average_packet_delay,
|
||||
debug_config.cover_traffic.loop_cover_traffic_average_delay,
|
||||
debug_config.average_ack_delay,
|
||||
debug_config.average_packet_delay,
|
||||
debug_config.loop_cover_traffic_average_delay,
|
||||
mix_tx,
|
||||
self_address,
|
||||
topology_accessor,
|
||||
);
|
||||
|
||||
if let Some(size) = debug_config.traffic.use_extended_packet_size {
|
||||
if let Some(size) = debug_config.use_extended_packet_size {
|
||||
log::debug!("Setting extended packet size: {:?}", size);
|
||||
stream.set_custom_packet_size(size.into());
|
||||
}
|
||||
@@ -338,9 +338,7 @@ where
|
||||
shared_key,
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
self.debug_config
|
||||
.gateway_connection
|
||||
.gateway_response_timeout,
|
||||
self.debug_config.gateway_response_timeout,
|
||||
self.bandwidth_controller.take(),
|
||||
shutdown,
|
||||
);
|
||||
@@ -502,7 +500,7 @@ where
|
||||
);
|
||||
Self::start_topology_refresher(
|
||||
topology_provider,
|
||||
self.debug_config.topology.topology_refresh_rate,
|
||||
self.debug_config.topology_refresh_rate,
|
||||
shared_topology_accessor.clone(),
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
@@ -538,7 +536,7 @@ where
|
||||
self_address,
|
||||
);
|
||||
|
||||
if let Some(size) = self.debug_config.traffic.use_extended_packet_size {
|
||||
if let Some(size) = self.debug_config.use_extended_packet_size {
|
||||
log::debug!("Setting extended packet size: {:?}", size);
|
||||
controller_config.set_custom_packet_size(size.into());
|
||||
}
|
||||
@@ -557,11 +555,7 @@ where
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
if !self
|
||||
.debug_config
|
||||
.cover_traffic
|
||||
.disable_loop_cover_traffic_stream
|
||||
{
|
||||
if !self.debug_config.disable_loop_cover_traffic_stream {
|
||||
Self::start_cover_traffic_stream(
|
||||
self.debug_config,
|
||||
self.key_manager.ack_key(),
|
||||
|
||||
@@ -30,12 +30,8 @@ async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
// it will only be happening on the very first run and in practice won't incur huge
|
||||
// costs since the storage is going to be empty
|
||||
let mem_store = CombinedReplyStorage::new(
|
||||
debug_config
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_storage_threshold,
|
||||
debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
debug_config.minimum_reply_surb_storage_threshold,
|
||||
debug_config.maximum_reply_surb_storage_threshold,
|
||||
);
|
||||
storage_backend
|
||||
.init_fresh(&mem_store)
|
||||
@@ -50,12 +46,8 @@ async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
fn setup_inactive_backend(debug_config: &DebugConfig) -> fs_backend::Backend {
|
||||
info!("creating inactive surb database");
|
||||
fs_backend::Backend::new_inactive(
|
||||
debug_config
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_storage_threshold,
|
||||
debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
debug_config.minimum_reply_surb_storage_threshold,
|
||||
debug_config.maximum_reply_surb_storage_threshold,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -153,35 +153,25 @@ impl Config {
|
||||
ack_key,
|
||||
self_recipient,
|
||||
packet_size: Default::default(),
|
||||
ack_wait_addition: base_client_debug_config.acknowledgements.ack_wait_addition,
|
||||
ack_wait_multiplier: base_client_debug_config
|
||||
.acknowledgements
|
||||
.ack_wait_multiplier,
|
||||
average_message_sending_delay: base_client_debug_config
|
||||
.traffic
|
||||
.message_sending_average_delay,
|
||||
average_packet_delay_duration: base_client_debug_config.traffic.average_packet_delay,
|
||||
average_ack_delay_duration: base_client_debug_config.acknowledgements.average_ack_delay,
|
||||
ack_wait_addition: base_client_debug_config.ack_wait_addition,
|
||||
ack_wait_multiplier: base_client_debug_config.ack_wait_multiplier,
|
||||
average_message_sending_delay: base_client_debug_config.message_sending_average_delay,
|
||||
average_packet_delay_duration: base_client_debug_config.average_packet_delay,
|
||||
average_ack_delay_duration: base_client_debug_config.average_ack_delay,
|
||||
disable_main_poisson_packet_distribution: base_client_debug_config
|
||||
.traffic
|
||||
.disable_main_poisson_packet_distribution,
|
||||
minimum_reply_surb_request_size: base_client_debug_config
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: base_client_debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: base_client_debug_config
|
||||
.reply_surbs
|
||||
.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period: base_client_debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_rerequest_waiting_period,
|
||||
maximum_reply_surb_drop_waiting_period: base_client_debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_drop_waiting_period,
|
||||
maximum_reply_surb_age: base_client_debug_config.reply_surbs.maximum_reply_surb_age,
|
||||
maximum_reply_key_age: base_client_debug_config.reply_surbs.maximum_reply_key_age,
|
||||
maximum_reply_surb_age: base_client_debug_config.maximum_reply_surb_age,
|
||||
maximum_reply_key_age: base_client_debug_config.maximum_reply_key_age,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,12 +35,8 @@ impl ReplyStorageBackend for Backend {
|
||||
) -> Result<Self, Self::StorageError> {
|
||||
Ok(Backend {
|
||||
empty: Empty {
|
||||
min_surb_threshold: debug_config
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,12 +35,8 @@ impl ReplyStorageBackend for Empty {
|
||||
_db_path: Option<PathBuf>,
|
||||
) -> Result<Self, Self::StorageError> {
|
||||
Ok(Self {
|
||||
min_surb_threshold: debug_config
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ use url::Url;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod old_config_v1_1_13;
|
||||
pub mod persistence;
|
||||
|
||||
pub const MISSING_VALUE: &str = "MISSING VALUE";
|
||||
@@ -211,12 +210,11 @@ impl<T> Config<T> {
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
||||
self.debug.average_packet_delay = Duration::from_millis(10);
|
||||
// basically don't really send cover messages
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay =
|
||||
Duration::from_millis(2_000_000);
|
||||
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2_000_000);
|
||||
// 250 "real" messages / s
|
||||
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
|
||||
self.debug.message_sending_average_delay = Duration::from_millis(4);
|
||||
}
|
||||
|
||||
pub fn with_disabled_cover_traffic(mut self, disabled: bool) -> Self {
|
||||
@@ -227,8 +225,8 @@ impl<T> Config<T> {
|
||||
}
|
||||
|
||||
pub fn set_no_cover_traffic(&mut self) {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
self.debug.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn set_custom_version(&mut self, version: &str) {
|
||||
@@ -313,93 +311,87 @@ impl<T> Config<T> {
|
||||
}
|
||||
|
||||
pub fn get_average_packet_delay(&self) -> Duration {
|
||||
self.debug.traffic.average_packet_delay
|
||||
self.debug.average_packet_delay
|
||||
}
|
||||
|
||||
pub fn get_average_ack_delay(&self) -> Duration {
|
||||
self.debug.acknowledgements.average_ack_delay
|
||||
self.debug.average_ack_delay
|
||||
}
|
||||
|
||||
pub fn get_ack_wait_multiplier(&self) -> f64 {
|
||||
self.debug.acknowledgements.ack_wait_multiplier
|
||||
self.debug.ack_wait_multiplier
|
||||
}
|
||||
|
||||
pub fn get_ack_wait_addition(&self) -> Duration {
|
||||
self.debug.acknowledgements.ack_wait_addition
|
||||
self.debug.ack_wait_addition
|
||||
}
|
||||
|
||||
pub fn get_loop_cover_traffic_average_delay(&self) -> Duration {
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay
|
||||
self.debug.loop_cover_traffic_average_delay
|
||||
}
|
||||
|
||||
pub fn get_message_sending_average_delay(&self) -> Duration {
|
||||
self.debug.traffic.message_sending_average_delay
|
||||
self.debug.message_sending_average_delay
|
||||
}
|
||||
|
||||
pub fn get_gateway_response_timeout(&self) -> Duration {
|
||||
self.debug.gateway_connection.gateway_response_timeout
|
||||
self.debug.gateway_response_timeout
|
||||
}
|
||||
|
||||
pub fn get_topology_refresh_rate(&self) -> Duration {
|
||||
self.debug.topology.topology_refresh_rate
|
||||
self.debug.topology_refresh_rate
|
||||
}
|
||||
|
||||
pub fn get_topology_resolution_timeout(&self) -> Duration {
|
||||
self.debug.topology.topology_resolution_timeout
|
||||
self.debug.topology_resolution_timeout
|
||||
}
|
||||
|
||||
pub fn get_disabled_loop_cover_traffic_stream(&self) -> bool {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream
|
||||
self.debug.disable_loop_cover_traffic_stream
|
||||
}
|
||||
|
||||
pub fn get_disabled_main_poisson_packet_distribution(&self) -> bool {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution
|
||||
self.debug.disable_main_poisson_packet_distribution
|
||||
}
|
||||
|
||||
pub fn get_use_extended_packet_size(&self) -> Option<ExtendedPacketSize> {
|
||||
self.debug.traffic.use_extended_packet_size
|
||||
self.debug.use_extended_packet_size
|
||||
}
|
||||
|
||||
pub fn get_minimum_reply_surb_storage_threshold(&self) -> usize {
|
||||
self.debug.reply_surbs.minimum_reply_surb_storage_threshold
|
||||
self.debug.minimum_reply_surb_storage_threshold
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_storage_threshold(&self) -> usize {
|
||||
self.debug.reply_surbs.maximum_reply_surb_storage_threshold
|
||||
self.debug.maximum_reply_surb_storage_threshold
|
||||
}
|
||||
|
||||
pub fn get_minimum_reply_surb_request_size(&self) -> u32 {
|
||||
self.debug.reply_surbs.minimum_reply_surb_request_size
|
||||
self.debug.minimum_reply_surb_request_size
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_request_size(&self) -> u32 {
|
||||
self.debug.reply_surbs.maximum_reply_surb_request_size
|
||||
self.debug.maximum_reply_surb_request_size
|
||||
}
|
||||
|
||||
pub fn get_maximum_allowed_reply_surb_request_size(&self) -> u32 {
|
||||
self.debug
|
||||
.reply_surbs
|
||||
.maximum_allowed_reply_surb_request_size
|
||||
self.debug.maximum_allowed_reply_surb_request_size
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_rerequest_waiting_period(&self) -> Duration {
|
||||
self.debug
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_rerequest_waiting_period
|
||||
self.debug.maximum_reply_surb_rerequest_waiting_period
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_drop_waiting_period(&self) -> Duration {
|
||||
self.debug
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_drop_waiting_period
|
||||
self.debug.maximum_reply_surb_drop_waiting_period
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_surb_age(&self) -> Duration {
|
||||
self.debug.reply_surbs.maximum_reply_surb_age
|
||||
self.debug.maximum_reply_surb_age
|
||||
}
|
||||
|
||||
pub fn get_maximum_reply_key_age(&self) -> Duration {
|
||||
self.debug.reply_surbs.maximum_reply_key_age
|
||||
self.debug.maximum_reply_key_age
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,63 +450,63 @@ impl From<nym_topology::gateway::Node> for GatewayEndpointConfig {
|
||||
pub struct Client<T> {
|
||||
/// Version of the client for which this configuration was created.
|
||||
#[serde(default = "missing_string_value")]
|
||||
pub version: String,
|
||||
version: String,
|
||||
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
pub id: String,
|
||||
id: String,
|
||||
|
||||
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
|
||||
/// to claim bandwidth without presenting bandwidth credentials.
|
||||
#[serde(default)]
|
||||
pub disabled_credentials_mode: bool,
|
||||
disabled_credentials_mode: bool,
|
||||
|
||||
/// Addresses to nyxd validators via which the client can communicate with the chain.
|
||||
#[serde(alias = "validator_urls")]
|
||||
pub nyxd_urls: Vec<Url>,
|
||||
nyxd_urls: Vec<Url>,
|
||||
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
|
||||
/// Path to file containing private identity key.
|
||||
pub private_identity_key_file: PathBuf,
|
||||
private_identity_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing public identity key.
|
||||
pub public_identity_key_file: PathBuf,
|
||||
public_identity_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing private encryption key.
|
||||
pub private_encryption_key_file: PathBuf,
|
||||
private_encryption_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing public encryption key.
|
||||
pub public_encryption_key_file: PathBuf,
|
||||
public_encryption_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing shared key derived with the specified gateway that is used
|
||||
/// for all communication with it.
|
||||
pub gateway_shared_key_file: PathBuf,
|
||||
gateway_shared_key_file: PathBuf,
|
||||
|
||||
/// Path to file containing key used for encrypting and decrypting the content of an
|
||||
/// acknowledgement so that nobody besides the client knows which packet it refers to.
|
||||
pub ack_key_file: PathBuf,
|
||||
ack_key_file: PathBuf,
|
||||
|
||||
/// Information regarding how the client should send data to gateway.
|
||||
pub gateway_endpoint: GatewayEndpointConfig,
|
||||
gateway_endpoint: GatewayEndpointConfig,
|
||||
|
||||
/// Path to the database containing bandwidth credentials of this client.
|
||||
pub database_path: PathBuf,
|
||||
database_path: PathBuf,
|
||||
|
||||
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
// this was set to use #[serde(default)] for the purposes of compatibility for multi-surbs introduced in 1.1.4.
|
||||
// if you're reading this message and we have already introduced some breaking changes, feel free
|
||||
// to remove that attribute since at this point the client configs should have gotten regenerated
|
||||
#[serde(default)]
|
||||
pub reply_surb_database_path: PathBuf,
|
||||
reply_surb_database_path: PathBuf,
|
||||
|
||||
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
||||
/// It is expected to use default value and hence .toml file should not redefine this field.
|
||||
pub nym_root_directory: PathBuf,
|
||||
nym_root_directory: PathBuf,
|
||||
|
||||
#[serde(skip)]
|
||||
pub super_struct: PhantomData<T>,
|
||||
super_struct: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for Client<T> {
|
||||
@@ -595,9 +587,9 @@ impl<T: NymConfig> Client<T> {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Logging {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Traffic {
|
||||
pub struct DebugConfig {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
@@ -605,74 +597,6 @@ pub struct Traffic {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
|
||||
/// Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
/// poisson distribution.
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
/// Controls whether the sent sphinx packet use a NON-DEFAULT bigger size.
|
||||
pub use_extended_packet_size: Option<ExtendedPacketSize>,
|
||||
}
|
||||
|
||||
impl Default for Traffic {
|
||||
fn default() -> Self {
|
||||
Traffic {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
use_extended_packet_size: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct CoverTraffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
|
||||
/// Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl Default for CoverTraffic {
|
||||
fn default() -> Self {
|
||||
CoverTraffic {
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct GatewayConnection {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for GatewayConnection {
|
||||
fn default() -> Self {
|
||||
GatewayConnection {
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Acknowledgements {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
@@ -690,21 +614,24 @@ pub struct Acknowledgements {
|
||||
/// In an ideal network with 0 latency, this value would have been 0.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub ack_wait_addition: Duration,
|
||||
}
|
||||
|
||||
impl Default for Acknowledgements {
|
||||
fn default() -> Self {
|
||||
Acknowledgements {
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Topology {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
#[serde(with = "humantime_serde")]
|
||||
@@ -715,20 +642,18 @@ pub struct Topology {
|
||||
/// did not reach its destination.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_resolution_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for Topology {
|
||||
fn default() -> Self {
|
||||
Topology {
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
|
||||
/// Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
/// poisson distribution.
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
/// Controls whether the sent sphinx packet use a NON-DEFAULT bigger size.
|
||||
pub use_extended_packet_size: Option<ExtendedPacketSize>,
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ReplySurbs {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
@@ -766,9 +691,29 @@ pub struct ReplySurbs {
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl Default for ReplySurbs {
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ExtendedPacketSize {
|
||||
Extended8,
|
||||
Extended16,
|
||||
Extended32,
|
||||
}
|
||||
|
||||
impl Default for DebugConfig {
|
||||
fn default() -> Self {
|
||||
ReplySurbs {
|
||||
DebugConfig {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
use_extended_packet_size: None,
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
@@ -783,52 +728,6 @@ impl Default for ReplySurbs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct DebugConfig {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: Traffic,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTraffic,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnection,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: Acknowledgements,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: Topology,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbs,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ExtendedPacketSize {
|
||||
Extended8,
|
||||
Extended16,
|
||||
Extended32,
|
||||
}
|
||||
|
||||
// it could be derived, sure, but I'd rather have an explicit implementation in case we had to change
|
||||
// something manually at some point
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for DebugConfig {
|
||||
fn default() -> Self {
|
||||
DebugConfig {
|
||||
traffic: Default::default(),
|
||||
cover_traffic: Default::default(),
|
||||
gateway_connection: Default::default(),
|
||||
acknowledgements: Default::default(),
|
||||
topology: Default::default(),
|
||||
reply_surbs: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtendedPacketSize> for PacketSize {
|
||||
fn from(size: ExtendedPacketSize) -> PacketSize {
|
||||
match size {
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::{
|
||||
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, ExtendedPacketSize,
|
||||
GatewayConnection, Logging, ReplySurbs, Topology, Traffic, DEFAULT_ACK_WAIT_ADDITION,
|
||||
DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY, DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
DEFAULT_MAXIMUM_REPLY_KEY_AGE, DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD, DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
DEFAULT_TOPOLOGY_REFRESH_RATE, DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
};
|
||||
use nym_config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13<T> {
|
||||
pub client: Client<T>,
|
||||
|
||||
#[serde(default)]
|
||||
logging: Logging,
|
||||
#[serde(default)]
|
||||
debug: OldDebugConfigV1_1_13,
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for OldConfigV1_1_13<T> {
|
||||
fn default() -> Self {
|
||||
OldConfigV1_1_13 {
|
||||
client: Client::<T>::default(),
|
||||
logging: Default::default(),
|
||||
debug: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct OldDebugConfigV1_1_13 {
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_packet_delay: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub average_ack_delay: Duration,
|
||||
|
||||
pub ack_wait_multiplier: f64,
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub ack_wait_addition: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub loop_cover_traffic_average_delay: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub message_sending_average_delay: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gateway_response_timeout: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_refresh_rate: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub topology_resolution_timeout: Duration,
|
||||
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
pub use_extended_packet_size: Option<ExtendedPacketSize>,
|
||||
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
|
||||
pub maximum_reply_surb_storage_threshold: usize,
|
||||
|
||||
pub minimum_reply_surb_request_size: u32,
|
||||
|
||||
pub maximum_reply_surb_request_size: u32,
|
||||
|
||||
pub maximum_allowed_reply_surb_request_size: u32,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_rerequest_waiting_period: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_drop_waiting_period: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_surb_age: Duration,
|
||||
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub maximum_reply_key_age: Duration,
|
||||
}
|
||||
|
||||
impl From<OldDebugConfigV1_1_13> for DebugConfig {
|
||||
fn from(value: OldDebugConfigV1_1_13) -> Self {
|
||||
DebugConfig {
|
||||
traffic: Traffic {
|
||||
average_packet_delay: value.average_packet_delay,
|
||||
message_sending_average_delay: value.message_sending_average_delay,
|
||||
disable_main_poisson_packet_distribution: value
|
||||
.disable_main_poisson_packet_distribution,
|
||||
use_extended_packet_size: value.use_extended_packet_size,
|
||||
},
|
||||
cover_traffic: CoverTraffic {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
|
||||
},
|
||||
gateway_connection: GatewayConnection {
|
||||
gateway_response_timeout: value.gateway_response_timeout,
|
||||
},
|
||||
acknowledgements: Acknowledgements {
|
||||
average_ack_delay: value.average_ack_delay,
|
||||
ack_wait_multiplier: value.ack_wait_multiplier,
|
||||
ack_wait_addition: value.ack_wait_addition,
|
||||
},
|
||||
topology: Topology {
|
||||
topology_refresh_rate: value.topology_refresh_rate,
|
||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||
},
|
||||
reply_surbs: ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: value.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: value
|
||||
.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period: value
|
||||
.maximum_reply_surb_rerequest_waiting_period,
|
||||
maximum_reply_surb_drop_waiting_period: value
|
||||
.maximum_reply_surb_drop_waiting_period,
|
||||
maximum_reply_surb_age: value.maximum_reply_surb_age,
|
||||
maximum_reply_key_age: value.maximum_reply_key_age,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OldDebugConfigV1_1_13 {
|
||||
fn default() -> Self {
|
||||
OldDebugConfigV1_1_13 {
|
||||
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
|
||||
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
|
||||
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
|
||||
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
|
||||
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
|
||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||
disable_loop_cover_traffic_stream: false,
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
use_extended_packet_size: None,
|
||||
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
|
||||
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
|
||||
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
|
||||
maximum_reply_surb_rerequest_waiting_period:
|
||||
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
|
||||
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
|
||||
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
|
||||
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> From<OldConfigV1_1_13<T>> for Config<U> {
|
||||
fn from(value: OldConfigV1_1_13<T>) -> Self {
|
||||
Config {
|
||||
client: Client {
|
||||
version: value.client.version,
|
||||
id: value.client.id,
|
||||
disabled_credentials_mode: value.client.disabled_credentials_mode,
|
||||
nyxd_urls: value.client.nyxd_urls,
|
||||
nym_api_urls: value.client.nym_api_urls,
|
||||
private_identity_key_file: value.client.private_identity_key_file,
|
||||
public_identity_key_file: value.client.public_identity_key_file,
|
||||
private_encryption_key_file: value.client.private_encryption_key_file,
|
||||
public_encryption_key_file: value.client.public_encryption_key_file,
|
||||
gateway_shared_key_file: value.client.gateway_shared_key_file,
|
||||
ack_key_file: value.client.ack_key_file,
|
||||
gateway_endpoint: value.client.gateway_endpoint,
|
||||
database_path: value.client.database_path,
|
||||
reply_surb_database_path: value.client.reply_surb_database_path,
|
||||
nym_root_directory: value.client.nym_root_directory,
|
||||
|
||||
super_struct: PhantomData,
|
||||
},
|
||||
logging: value.logging,
|
||||
debug: value.debug.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,14 +112,14 @@ where
|
||||
{
|
||||
let id = config.get_id();
|
||||
|
||||
// If we are not going to register gateway, and an explicitly chosen gateway is not passed in,
|
||||
// If we are not going to register gateway, and an explicitly chosed gateway is not passed in,
|
||||
// load the existing configuration file
|
||||
if !register_gateway && user_chosen_gateway_id.is_none() {
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
return load_existing_gateway_config::<C>(&id);
|
||||
}
|
||||
|
||||
// Else, we proceed by querying the nym-api
|
||||
// Else, we preceed by querying the nym-api
|
||||
let gateway = helpers::query_gateway_details(
|
||||
config.get_nym_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -15,7 +15,6 @@ pub use client_core::config::Config as BaseConfig;
|
||||
pub use client_core::config::MISSING_VALUE;
|
||||
pub use client_core::config::{DebugConfig, GatewayEndpointConfig};
|
||||
|
||||
pub mod old_config_v1_1_13;
|
||||
mod template;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, Socket};
|
||||
use client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
socket: Socket,
|
||||
}
|
||||
|
||||
impl NymConfig for OldConfigV1_1_13 {
|
||||
fn template() -> &'static str {
|
||||
// not intended to be used
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.expect("Failed to evaluate $HOME value")
|
||||
.join(".nym")
|
||||
.join("clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for Config {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
Config {
|
||||
base: value.base.into(),
|
||||
socket: value.socket,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,15 +110,10 @@ host = '{{ socket.host }}'
|
||||
|
||||
[debug]
|
||||
|
||||
[debug.traffic]
|
||||
average_packet_delay = '{{ debug.traffic.average_packet_delay }}'
|
||||
message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}'
|
||||
|
||||
[debug.acknowledgements]
|
||||
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
|
||||
|
||||
[debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
average_packet_delay = '{{ debug.average_packet_delay }}'
|
||||
average_ack_delay = '{{ debug.average_ack_delay }}'
|
||||
loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}'
|
||||
message_sending_average_delay = '{{ debug.message_sending_average_delay }}'
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::config::Config,
|
||||
commands::{override_config, OverrideConfig},
|
||||
@@ -122,9 +121,6 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
|
||||
|
||||
let already_init = Config::default_config_file_path(id).exists();
|
||||
if already_init {
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
println!("Client \"{id}\" was already initialised before");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use crate::client::config::{BaseConfig, Config};
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_config::OptionalSet;
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
@@ -104,20 +102,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(());
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated: Config = old_config.into();
|
||||
updated.save_to_file(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::{config::Config, SocketClient},
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::ClientError,
|
||||
};
|
||||
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
@@ -100,10 +100,6 @@ fn version_check(cfg: &Config) -> bool {
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let id = &args.id;
|
||||
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
|
||||
let mut config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -15,7 +15,6 @@ use std::fmt::Debug;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub mod old_config_v1_1_13;
|
||||
mod template;
|
||||
|
||||
const DEFAULT_CONNECTION_START_SURBS: u32 = 20;
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::{Config, Socks5, Socks5Debug};
|
||||
use client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
socks5: Socks5,
|
||||
|
||||
#[serde(default)]
|
||||
socks5_debug: Socks5Debug,
|
||||
}
|
||||
|
||||
impl NymConfig for OldConfigV1_1_13 {
|
||||
fn template() -> &'static str {
|
||||
// not intended to be used
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(feature = "mobile"))]
|
||||
let base_dir = dirs::home_dir().expect("Failed to evaluate $HOME value");
|
||||
#[cfg(feature = "mobile")]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
|
||||
fn try_default_root_directory() -> Option<PathBuf> {
|
||||
dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
|
||||
}
|
||||
|
||||
fn root_directory(&self) -> PathBuf {
|
||||
self.base.client.nym_root_directory.clone()
|
||||
}
|
||||
|
||||
fn config_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("config")
|
||||
}
|
||||
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory()
|
||||
.join(&self.base.client.id)
|
||||
.join("data")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for Config {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
Config {
|
||||
base: value.base.into(),
|
||||
socks5: value.socks5,
|
||||
socks5_debug: value.socks5_debug,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,15 +114,10 @@ send_anonymously = {{ socks5.send_anonymously }}
|
||||
|
||||
[debug]
|
||||
|
||||
[debug.traffic]
|
||||
average_packet_delay = '{{ debug.traffic.average_packet_delay }}'
|
||||
message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}'
|
||||
|
||||
[debug.acknowledgements]
|
||||
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
|
||||
|
||||
[debug.cover_traffic]
|
||||
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
|
||||
average_packet_delay = '{{ debug.average_packet_delay }}'
|
||||
average_ack_delay = '{{ debug.average_ack_delay }}'
|
||||
loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}'
|
||||
message_sending_average_delay = '{{ debug.message_sending_average_delay }}'
|
||||
|
||||
"#
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::config::Config,
|
||||
commands::{override_config, OverrideConfig},
|
||||
@@ -125,9 +124,6 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
|
||||
|
||||
let already_init = Config::default_config_file_path(id).exists();
|
||||
if already_init {
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
println!("SOCKS5 client \"{id}\" was already initialised before");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use crate::client::config::{BaseConfig, Config};
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_config::OptionalSet;
|
||||
use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
@@ -103,20 +101,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(());
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated: Config = old_config.into();
|
||||
updated.save_to_file(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_upgrade_v1_1_13_config;
|
||||
use crate::{
|
||||
client::{config::Config, NymClient},
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::Socks5ClientError,
|
||||
};
|
||||
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
@@ -108,10 +108,6 @@ fn version_check(cfg: &Config) -> bool {
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let id = &args.id;
|
||||
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_v1_1_13_config(id)?;
|
||||
|
||||
let mut config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
MixNodeDetails,
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
OriginalVestingResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
@@ -32,10 +33,11 @@ import {
|
||||
RewardingParams,
|
||||
StakeSaturationResponse,
|
||||
UnbondedMixnodeResponse,
|
||||
VestingAccountInfo,
|
||||
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode
|
||||
} from '@nymproject/types';
|
||||
import QueryClient from './query-client';
|
||||
import SigningClient, { ISigningClient } from './signing-client';
|
||||
import { ContractState } from './types/shared';
|
||||
|
||||
export interface INymClient {
|
||||
readonly mixnetContract: string;
|
||||
@@ -204,7 +206,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let mixNodes: UnbondedMixnodeResponse[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedUnbondedMixnodesResponse = await this.client.getUnbondedMixNodes(
|
||||
this.mixnetContract,
|
||||
@@ -227,7 +229,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let mixNodes: MixNodeBond[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixNodeBondResponse = await this.client.getMixNodeBonds(
|
||||
this.mixnetContract,
|
||||
@@ -249,7 +251,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let mixNodes: MixNodeDetails[] = [];
|
||||
const limit = 50;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixNodeDetailsResponse = await this.client.getMixNodesDetailed(
|
||||
this.mixnetContract,
|
||||
@@ -281,7 +283,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedMixDelegationsResponse = await this.client.getMixNodeDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
@@ -304,7 +306,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedDelegatorDelegationsResponse = await this.client.getDelegatorDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
@@ -327,7 +329,7 @@ export default class ValidatorClient implements INymClient {
|
||||
let delegations: Delegation[] = [];
|
||||
const limit = 250;
|
||||
let startAfter;
|
||||
for (;;) {
|
||||
for (; ;) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pagedResponse: PagedAllDelegationsResponse = await this.client.getAllDelegationsPaged(
|
||||
this.mixnetContract,
|
||||
@@ -514,4 +516,97 @@ export default class ValidatorClient implements INymClient {
|
||||
this.assertSigning();
|
||||
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
||||
}
|
||||
|
||||
|
||||
// VESTING
|
||||
// TODO - MOVE TO A DIFFERENT FILE
|
||||
|
||||
|
||||
public async getVestingAccountsPaged(): Promise<VestingAccountsPaged> {
|
||||
return this.client.getVestingAccountsPaged(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getVestingAmountsAccountsPaged(): Promise<VestingAccountsCoinPaged> {
|
||||
return this.client.getVestingAmountsAccountsPaged(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getLockedTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getLockedTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSpendableTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getSpendableTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getVestedTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getVestedTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getVestingTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getVestingTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSpendableVestedTokens(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getSpendableVestedTokens(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getSpendableRewards(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getSpendableRewards(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getDelegatedCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getDelegatedCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getPledgedCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getPledgedCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getStakedCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getStakedCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getWithdrawnCoins(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getWithdrawnCoins(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getStartTime(vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.getStartTime(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getEndTime(vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.getEndTime(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getOriginalVestingDetails(vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.client.getOriginalVestingDetails(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getHistoricStakingRewards(vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.getHistoricStakingRewards(this.vestingContract, vestingAccountAddress);
|
||||
}
|
||||
|
||||
public async getAccountDetails(address: string): Promise<VestingAccountInfo> {
|
||||
return this.client.getAccountDetails(this.vestingContract, address);
|
||||
}
|
||||
|
||||
public async getMixnode(address: string): Promise<VestingAccountNode> {
|
||||
return this.client.getMixnode(this.vestingContract, address);
|
||||
}
|
||||
|
||||
public async getGateway(address: string): Promise<VestingAccountNode> {
|
||||
return this.client.getGateway(this.vestingContract, address);
|
||||
}
|
||||
|
||||
public async getDelegationTimes(mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
|
||||
return this.client.getDelegationTimes(this.vestingContract, mix_id, delegatorAddress);
|
||||
}
|
||||
|
||||
public async getAllDelegations(): Promise<Delegations> {
|
||||
return this.client.getAllDelegations(this.vestingContract);
|
||||
}
|
||||
|
||||
public async getCurrentVestingPeriod(address: string): Promise<Period> {
|
||||
return this.client.getCurrentVestingPeriod(this.vestingContract, address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*/
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { INyxdQuery } from './query-client';
|
||||
import { Delegation, RewardingParams, StakeSaturationResponse } from '@nymproject/types';
|
||||
import {
|
||||
Delegation, OriginalVestingResponse, RewardingParams, StakeSaturationResponse, VestingAccountInfo,
|
||||
UnbondedMixnodeResponse,
|
||||
GatewayOwnershipResponse,
|
||||
MixnetContractVersion,
|
||||
@@ -18,8 +18,10 @@ import {
|
||||
PagedMixNodeDetailsResponse,
|
||||
PagedUnbondedMixnodesResponse,
|
||||
LayerDistribution,
|
||||
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode
|
||||
} from '@nymproject/types';
|
||||
import { ContractState, SmartContractQuery } from './types/shared';
|
||||
import { SmartContractQuery } from './types/shared';
|
||||
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
|
||||
export default class NyxdQuerier implements INyxdQuery {
|
||||
client: SmartContractQuery;
|
||||
@@ -188,4 +190,136 @@ export default class NyxdQuerier implements INyxdQuery {
|
||||
vesting_account_address: vestingAccountAddress,
|
||||
});
|
||||
}
|
||||
|
||||
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_accounts_paged: {}
|
||||
});
|
||||
}
|
||||
|
||||
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_accounts_vesting_coins_paged: {}
|
||||
});
|
||||
}
|
||||
|
||||
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
locked_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
spendable_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_vested_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_vesting_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_spendable_vested_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_spendable_reward_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_delegated_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_pledged_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_staked_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_withdrawn_coins: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_start_time: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_end_time: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_original_vesting: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_historical_vesting_staking_reward: { vesting_account_address: vestingAccountAddress }
|
||||
});
|
||||
}
|
||||
|
||||
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_account: { address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_mixnode: { address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_gateway: { address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getDelegationTimes(vestingContractAddress: string, mix_id: number, address: string): Promise<DelegationTimes> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_delegation_times: { mix_id: mix_id, address: address }
|
||||
});
|
||||
}
|
||||
|
||||
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_all_delegations: {}
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
|
||||
return this.client.queryContractSmart(vestingContractAddress, {
|
||||
get_current_vesting_period: { address: address }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,15 @@ import {
|
||||
UnbondedMixnodeResponse,
|
||||
MixNodeBond,
|
||||
MixNodeRewarding,
|
||||
OriginalVestingResponse,
|
||||
VestingAccountInfo,
|
||||
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode
|
||||
} from '@nymproject/types';
|
||||
import NymApiQuerier, { INymApiQuery } from './nym-api-querier';
|
||||
import { ContractState, ICosmWasmQuery } from './types/shared';
|
||||
import { ICosmWasmQuery } from './types/shared';
|
||||
import { RewardingParams } from '@nymproject/types';
|
||||
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
|
||||
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
|
||||
export interface INyxdQuery {
|
||||
// nym-specific implemented inside NymQuerier
|
||||
@@ -68,7 +72,7 @@ export interface INyxdQuery {
|
||||
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding>;
|
||||
}
|
||||
|
||||
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery {}
|
||||
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery { }
|
||||
|
||||
export default class QueryClient extends CosmWasmClient implements IQueryClient {
|
||||
private nyxdQuerier: NyxdQuerier;
|
||||
@@ -199,4 +203,92 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
|
||||
return this.nyxdQuerier.getSpendableCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
|
||||
return this.nyxdQuerier.getVestingAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
|
||||
return this.nyxdQuerier.getVestingAmountsAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getLockedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestingTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getDelegatedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getPledgedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getStakedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getWithdrawnCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getStartTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getEndTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.nyxdQuerier.getOriginalVestingDetails(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getHistoricStakingRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
|
||||
return this.nyxdQuerier.getAccountDetails(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getMixnode(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getGateway(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getDelegationTimes(vestingContractAddress: string, mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
|
||||
return this.nyxdQuerier.getDelegationTimes(vestingContractAddress, mix_id, delegatorAddress);
|
||||
}
|
||||
|
||||
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
|
||||
return this.nyxdQuerier.getAllDelegations(vestingContractAddress);
|
||||
}
|
||||
|
||||
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
|
||||
return this.nyxdQuerier.getCurrentVestingPeriod(vestingContractAddress, address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
MixNodeDetails,
|
||||
MixNodeRewarding,
|
||||
MixOwnershipResponse,
|
||||
OriginalVestingResponse,
|
||||
PagedAllDelegationsResponse,
|
||||
PagedDelegatorDelegationsResponse,
|
||||
PagedGatewayResponse,
|
||||
@@ -38,9 +39,10 @@ import {
|
||||
PagedUnbondedMixnodesResponse,
|
||||
RewardingParams,
|
||||
UnbondedMixnodeResponse,
|
||||
VestingAccountInfo,
|
||||
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode
|
||||
} from '@nymproject/types';
|
||||
import NymApiQuerier from './nym-api-querier';
|
||||
import { ContractState } from './types/shared';
|
||||
|
||||
// methods exposed by `SigningCosmWasmClient`
|
||||
export interface ICosmWasmSigning {
|
||||
@@ -243,7 +245,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
// query related:
|
||||
|
||||
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion> {
|
||||
return this.getContractVersion(mixnetContractAddress);
|
||||
return this.nyxdQuerier.getContractVersion(mixnetContractAddress);
|
||||
}
|
||||
|
||||
getMixNodeBonds(
|
||||
@@ -508,4 +510,94 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
memo,
|
||||
);
|
||||
}
|
||||
|
||||
// vesting related
|
||||
|
||||
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
|
||||
return this.nyxdQuerier.getVestingAccountsPaged(vestingContractAddress);
|
||||
};
|
||||
|
||||
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
|
||||
return this.nyxdQuerier.getVestingAmountsAccountsPaged(vestingContractAddress);
|
||||
}
|
||||
|
||||
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getLockedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getVestingTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableVestedTokens(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getSpendableRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getDelegatedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getPledgedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getStakedCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getWithdrawnCoins(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getStartTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
|
||||
return this.nyxdQuerier.getEndTime(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
|
||||
return this.nyxdQuerier.getOriginalVestingDetails(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
|
||||
return this.nyxdQuerier.getHistoricStakingRewards(vestingContractAddress, vestingAccountAddress);
|
||||
}
|
||||
|
||||
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
|
||||
return this.nyxdQuerier.getAccountDetails(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getMixnode(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
|
||||
return this.nyxdQuerier.getGateway(vestingContractAddress, address);
|
||||
}
|
||||
|
||||
getDelegationTimes(vestingContractAddress: string, mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
|
||||
return this.nyxdQuerier.getDelegationTimes(vestingContractAddress, mix_id, delegatorAddress);
|
||||
}
|
||||
|
||||
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
|
||||
return this.nyxdQuerier.getAllDelegations(vestingContractAddress);
|
||||
}
|
||||
|
||||
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
|
||||
return this.nyxdQuerier.getCurrentVestingPeriod(vestingContractAddress, address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
|
||||
import expect from 'expect';
|
||||
|
||||
export const amountDemon = {
|
||||
amount: expect.any(String),
|
||||
denom: expect.any(String)
|
||||
denom: expect.any(String),
|
||||
amount: expect.any(String)
|
||||
}
|
||||
|
||||
export const delegation = {
|
||||
@@ -159,7 +160,6 @@ export const layerDistribution = {
|
||||
layer3: expect.any(Number)
|
||||
}
|
||||
|
||||
|
||||
export const intervalRewardParams = {
|
||||
reward_pool: expect.any(Number),
|
||||
staking_supply: expect.any(Number),
|
||||
@@ -176,3 +176,79 @@ export const rewardingParams = {
|
||||
rewarded_set_size: expect.any(Number),
|
||||
active_set_size: expect.any(Number)
|
||||
}
|
||||
|
||||
export const VestAccounts = [{
|
||||
account_id: expect.any(String),
|
||||
owner: expect.any(String)
|
||||
}]
|
||||
|
||||
export const VestAccountCoin = [{
|
||||
account_id: expect.any(String),
|
||||
owner: expect.any(String),
|
||||
still_vesting: Coin
|
||||
}]
|
||||
|
||||
export const vestingAccountsPaged = {
|
||||
accounts: VestAccounts,
|
||||
start_next_after: expect.any(String)
|
||||
}
|
||||
|
||||
export const VestingCoinAccounts = {
|
||||
accounts: VestAccountCoin,
|
||||
start_next_after: expect.any(String)
|
||||
}
|
||||
|
||||
export const OriginalVestingDetails = {
|
||||
amount: Coin,
|
||||
number_of_periods: expect.any(Number),
|
||||
period_duration: expect.any(Number)
|
||||
}
|
||||
|
||||
export const PledgeCap = {
|
||||
percent: expect.any(String) || null,
|
||||
};
|
||||
|
||||
export const Periods = [{
|
||||
period_seconds: expect.any(Number),
|
||||
start_time: expect.any(Number),
|
||||
}]
|
||||
|
||||
export const VestingAccountDetails = {
|
||||
owner_address: expect.any(String),
|
||||
staking_address: expect.any(String) || null,
|
||||
start_time: expect.any(String),
|
||||
periods: Periods,
|
||||
coin: Coin,
|
||||
storage_key: expect.any(Number),
|
||||
pledge_cap: PledgeCap
|
||||
}
|
||||
|
||||
export const Node = {
|
||||
amount: Coin,
|
||||
block_time: expect.any(String)
|
||||
}
|
||||
|
||||
export type VestingPeriod = 'Before' | { In: number } | 'After';
|
||||
|
||||
export const DelegationTimestamps = [
|
||||
expect.any(Number)
|
||||
]
|
||||
|
||||
export const DelegatorTimes = {
|
||||
owner: expect.any(String),
|
||||
account_id: expect.any(Number),
|
||||
mix_id: expect.any(Number),
|
||||
delegation_timestamps: DelegationTimestamps
|
||||
}
|
||||
|
||||
export const DelegationBlock = [{
|
||||
account_id: expect.any(Number),
|
||||
amount: expect.any(String),
|
||||
block_timestamp: expect.any(Number),
|
||||
mix_id: expect.any(Number)
|
||||
}]
|
||||
|
||||
export const Delegations = {
|
||||
delegations: DelegationBlock,
|
||||
start_next_after: expect.any(String) || null
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import expect from 'expect';
|
||||
import ValidatorClient from '../../index';
|
||||
import { amountDemon, Delegations, DelegatorTimes, Node, OriginalVestingDetails, VestingAccountDetails, vestingAccountsPaged, VestingCoinAccounts, VestingPeriod } from '../expectedResponses';
|
||||
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
@@ -19,10 +20,149 @@ describe('Vesting queries', () => {
|
||||
);
|
||||
});
|
||||
|
||||
const vesting_account_address = 'n14juvj7llvx8eppypnqj6xlrgwss9wfrcuy0nkv';
|
||||
const mixnodeowner = 'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70';
|
||||
const gatewayowner = 'n1un9cuvw9e3xqratmde4j55ucksev0dkeruq800';
|
||||
const mix_id = 79;
|
||||
|
||||
it('can query for contract version', async () => {
|
||||
const contract = await client.getVestingContractVersion();
|
||||
expect(contract).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get the balance on the account', () => {});
|
||||
// TODO see if we can use AccountEntry type here instead
|
||||
it('can get all accounts paged', async () => {
|
||||
const accounts = await client.getVestingAccountsPaged();
|
||||
expect(Object.keys(accounts)).toEqual(Object.keys(vestingAccountsPaged));
|
||||
expect(accounts).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get coins for all accounts paged', async () => {
|
||||
const accounts = await client.getVestingAmountsAccountsPaged();
|
||||
expect(Object.keys(accounts)).toEqual(Object.keys(VestingCoinAccounts));
|
||||
expect(accounts).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get locked tokens for an account', async () => {
|
||||
const locked = await client.getLockedTokens(vesting_account_address);
|
||||
expect(Object.keys(locked)).toEqual(Object.keys(amountDemon));
|
||||
expect(locked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get spendable tokens for an account', async () => {
|
||||
const spendable = await client.getSpendableTokens(vesting_account_address);
|
||||
expect(Object.keys(spendable)).toEqual(Object.keys(amountDemon));
|
||||
expect(spendable).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get vested tokens for an account', async () => {
|
||||
const vested = await client.getVestedTokens(vesting_account_address);
|
||||
expect(Object.keys(vested)).toEqual(Object.keys(amountDemon));
|
||||
expect(vested).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get vesting tokens for an account', async () => {
|
||||
const vesting = await client.getVestingTokens(vesting_account_address);
|
||||
expect(Object.keys(vesting)).toEqual(Object.keys(amountDemon));
|
||||
expect(vesting).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get spendable vested tokens for an account', async () => {
|
||||
const spendable = await client.getSpendableVestedTokens(vesting_account_address);
|
||||
expect(Object.keys(spendable)).toEqual(Object.keys(amountDemon));
|
||||
expect(spendable).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get spendable rewards for an account', async () => {
|
||||
const rewards = await client.getSpendableRewards(vesting_account_address);
|
||||
expect(Object.keys(rewards)).toEqual(Object.keys(amountDemon));
|
||||
expect(rewards).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get delegated coins', async () => {
|
||||
const delegated = await client.getDelegatedCoins(vesting_account_address);
|
||||
expect(Object.keys(delegated)).toEqual(Object.keys(amountDemon));
|
||||
expect(delegated).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get pledged coins', async () => {
|
||||
const pledged = await client.getPledgedCoins(vesting_account_address);
|
||||
expect(Object.keys(pledged)).toEqual(Object.keys(amountDemon));
|
||||
expect(pledged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get staked coins', async () => {
|
||||
const staked = await client.getStakedCoins(vesting_account_address);
|
||||
expect(Object.keys(staked)).toEqual(Object.keys(amountDemon));
|
||||
expect(staked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get withdrawn coins', async () => {
|
||||
const withdrawn = await client.getWithdrawnCoins(vesting_account_address);
|
||||
expect(Object.keys(withdrawn)).toEqual(Object.keys(amountDemon));
|
||||
expect(withdrawn).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get start time of an account', async () => {
|
||||
const time = await client.getStartTime(vesting_account_address);
|
||||
expect(typeof time).toBe("string");
|
||||
expect(time).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get end time of an account', async () => {
|
||||
const time = await client.getEndTime(vesting_account_address);
|
||||
expect(typeof time).toBe("string");
|
||||
expect(time).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get account original vesting details', async () => {
|
||||
const original = await client.getOriginalVestingDetails(vesting_account_address);
|
||||
expect(Object.keys(original)).toEqual(Object.keys(OriginalVestingDetails));
|
||||
expect(original).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get historic vesting staking rewards', async () => {
|
||||
const rewards = await client.getHistoricStakingRewards(vesting_account_address);
|
||||
expect(Object.keys(rewards)).toEqual(Object.keys(amountDemon));
|
||||
expect(rewards).toBeTruthy();
|
||||
});
|
||||
|
||||
// TODO see if we can use "VestingAccountInfo" type here instead
|
||||
it('can get account details', async () => {
|
||||
const account = await client.getAccountDetails(vesting_account_address);
|
||||
expect(Object.keys(account)).toEqual(Object.keys(VestingAccountDetails));
|
||||
expect(account).toBeTruthy();
|
||||
});
|
||||
|
||||
// TODO add option for if account has no mixnode and expected is null
|
||||
it('can get mixnode', async () => {
|
||||
const mixnode = await client.getMixnode(mixnodeowner);
|
||||
expect(Object.keys(mixnode)).toEqual(Object.keys(Node));
|
||||
expect(mixnode).toBeTruthy();
|
||||
});
|
||||
|
||||
// TODO add option for if account has no gateway and expected is null
|
||||
it.skip('can get gateway', async () => {
|
||||
const gateway = await client.getGateway(gatewayowner);
|
||||
expect(Object.keys(gateway)).toEqual(Object.keys(Node));
|
||||
expect(gateway).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get delegations times', async () => {
|
||||
const delegation = await client.getDelegationTimes(mix_id, mixnodeowner);
|
||||
expect(Object.keys(delegation)).toEqual(Object.keys(DelegatorTimes));
|
||||
expect(delegation).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get all delegations', async () => {
|
||||
const delegation = await client.getAllDelegations();
|
||||
expect(Object.keys(delegation)).toEqual(Object.keys(Delegations));
|
||||
expect(delegation).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can get current vesting period', async () => {
|
||||
const period = await client.getCurrentVestingPeriod(gatewayowner);
|
||||
expect(period).toEqual(expect.anything() as unknown as VestingPeriod);
|
||||
expect(period).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,15 +3,8 @@
|
||||
|
||||
// due to expansion of #[wasm_bindgen] macro on `Debug` Config struct
|
||||
#![allow(clippy::drop_non_drop)]
|
||||
// another issue due to #[wasm_bindgen] and `Copy` trait
|
||||
#![allow(clippy::drop_copy)]
|
||||
|
||||
use client_core::config::{
|
||||
Acknowledgements as ConfigAcknowledgements, CoverTraffic as ConfigCoverTraffic,
|
||||
DebugConfig as ConfigDebug, ExtendedPacketSize, GatewayConnection as ConfigGatewayConnection,
|
||||
GatewayEndpointConfig, ReplySurbs as ConfigReplySurbs, Topology as ConfigTopology,
|
||||
Traffic as ConfigTraffic,
|
||||
};
|
||||
use client_core::config::{DebugConfig as ConfigDebug, ExtendedPacketSize, GatewayEndpointConfig};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -55,124 +48,15 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
// just a helper structure to more easily pass through the JS boundary
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Traffic {
|
||||
pub struct Debug {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
/// until the packet reaches its destination.
|
||||
pub average_packet_delay_ms: u64,
|
||||
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
pub message_sending_average_delay_ms: u64,
|
||||
|
||||
/// Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
/// poisson distribution.
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
|
||||
pub use_extended_packet_size: bool,
|
||||
}
|
||||
|
||||
impl From<Traffic> for ConfigTraffic {
|
||||
fn from(traffic: Traffic) -> Self {
|
||||
let use_extended_packet_size = traffic
|
||||
.use_extended_packet_size
|
||||
.then(|| ExtendedPacketSize::Extended32);
|
||||
|
||||
ConfigTraffic {
|
||||
average_packet_delay: Duration::from_millis(traffic.average_packet_delay_ms),
|
||||
message_sending_average_delay: Duration::from_millis(
|
||||
traffic.message_sending_average_delay_ms,
|
||||
),
|
||||
disable_main_poisson_packet_distribution: traffic
|
||||
.disable_main_poisson_packet_distribution,
|
||||
use_extended_packet_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigTraffic> for Traffic {
|
||||
fn from(traffic: ConfigTraffic) -> Self {
|
||||
Traffic {
|
||||
average_packet_delay_ms: traffic.average_packet_delay.as_millis() as u64,
|
||||
message_sending_average_delay_ms: traffic.message_sending_average_delay.as_millis()
|
||||
as u64,
|
||||
disable_main_poisson_packet_distribution: traffic
|
||||
.disable_main_poisson_packet_distribution,
|
||||
use_extended_packet_size: traffic.use_extended_packet_size.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct CoverTraffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
pub loop_cover_traffic_average_delay_ms: u64,
|
||||
|
||||
/// Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
}
|
||||
|
||||
impl From<CoverTraffic> for ConfigCoverTraffic {
|
||||
fn from(cover_traffic: CoverTraffic) -> Self {
|
||||
ConfigCoverTraffic {
|
||||
loop_cover_traffic_average_delay: Duration::from_millis(
|
||||
cover_traffic.loop_cover_traffic_average_delay_ms,
|
||||
),
|
||||
disable_loop_cover_traffic_stream: cover_traffic.disable_loop_cover_traffic_stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigCoverTraffic> for CoverTraffic {
|
||||
fn from(cover_traffic: ConfigCoverTraffic) -> Self {
|
||||
CoverTraffic {
|
||||
loop_cover_traffic_average_delay_ms: cover_traffic
|
||||
.loop_cover_traffic_average_delay
|
||||
.as_millis() as u64,
|
||||
disable_loop_cover_traffic_stream: cover_traffic.disable_loop_cover_traffic_stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct GatewayConnection {
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
pub gateway_response_timeout_ms: u64,
|
||||
}
|
||||
|
||||
impl From<GatewayConnection> for ConfigGatewayConnection {
|
||||
fn from(gateway_connection: GatewayConnection) -> Self {
|
||||
ConfigGatewayConnection {
|
||||
gateway_response_timeout: Duration::from_millis(
|
||||
gateway_connection.gateway_response_timeout_ms,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigGatewayConnection> for GatewayConnection {
|
||||
fn from(gateway_connection: ConfigGatewayConnection) -> Self {
|
||||
GatewayConnection {
|
||||
gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis()
|
||||
as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Acknowledgements {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
@@ -188,31 +72,21 @@ pub struct Acknowledgements {
|
||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||
/// In an ideal network with 0 latency, this value would have been 0.
|
||||
pub ack_wait_addition_ms: u64,
|
||||
}
|
||||
|
||||
impl From<Acknowledgements> for ConfigAcknowledgements {
|
||||
fn from(acknowledgements: Acknowledgements) -> Self {
|
||||
ConfigAcknowledgements {
|
||||
average_ack_delay: Duration::from_millis(acknowledgements.average_ack_delay_ms),
|
||||
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
|
||||
ack_wait_addition: Duration::from_millis(acknowledgements.ack_wait_addition_ms),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take for another loop cover traffic message to be sent.
|
||||
pub loop_cover_traffic_average_delay_ms: u64,
|
||||
|
||||
impl From<ConfigAcknowledgements> for Acknowledgements {
|
||||
fn from(acknowledgements: ConfigAcknowledgements) -> Self {
|
||||
Acknowledgements {
|
||||
average_ack_delay_ms: acknowledgements.average_ack_delay.as_millis() as u64,
|
||||
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
|
||||
ack_wait_addition_ms: acknowledgements.ack_wait_addition.as_millis() as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// it is going to take another 'real traffic stream' message to be sent.
|
||||
/// If no real packets are available and cover traffic is enabled,
|
||||
/// a loop cover message is sent instead in order to preserve the rate.
|
||||
pub message_sending_average_delay_ms: u64,
|
||||
|
||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||
/// before giving up on it.
|
||||
pub gateway_response_timeout_ms: u64,
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Topology {
|
||||
/// The uniform delay every which clients are querying the directory server
|
||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||
pub topology_refresh_rate_ms: u64,
|
||||
@@ -221,31 +95,18 @@ pub struct Topology {
|
||||
/// path. This timeout determines waiting period until it is decided that the packet
|
||||
/// did not reach its destination.
|
||||
pub topology_resolution_timeout_ms: u64,
|
||||
}
|
||||
|
||||
impl From<Topology> for ConfigTopology {
|
||||
fn from(topology: Topology) -> Self {
|
||||
ConfigTopology {
|
||||
topology_refresh_rate: Duration::from_millis(topology.topology_refresh_rate_ms),
|
||||
topology_resolution_timeout: Duration::from_millis(
|
||||
topology.topology_resolution_timeout_ms,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay_ms])
|
||||
pub disable_loop_cover_traffic_stream: bool,
|
||||
|
||||
impl From<ConfigTopology> for Topology {
|
||||
fn from(topology: ConfigTopology) -> Self {
|
||||
Topology {
|
||||
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64,
|
||||
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
/// poisson distribution.
|
||||
pub disable_main_poisson_packet_distribution: bool,
|
||||
|
||||
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
|
||||
pub use_extended_packet_size: bool,
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ReplySurbs {
|
||||
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
/// It can only allow to go below that value if its to request additional reply surbs.
|
||||
pub minimum_reply_surb_storage_threshold: usize,
|
||||
@@ -279,80 +140,46 @@ pub struct ReplySurbs {
|
||||
pub maximum_reply_key_age_ms: u64,
|
||||
}
|
||||
|
||||
impl From<ReplySurbs> for ConfigReplySurbs {
|
||||
fn from(reply_surbs: ReplySurbs) -> Self {
|
||||
ConfigReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: reply_surbs.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: reply_surbs
|
||||
.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period: Duration::from_millis(
|
||||
reply_surbs.maximum_reply_surb_rerequest_waiting_period_ms,
|
||||
),
|
||||
maximum_reply_surb_drop_waiting_period: Duration::from_millis(
|
||||
reply_surbs.maximum_reply_surb_drop_waiting_period_ms,
|
||||
),
|
||||
maximum_reply_surb_age: Duration::from_millis(reply_surbs.maximum_reply_surb_age_ms),
|
||||
maximum_reply_key_age: Duration::from_millis(reply_surbs.maximum_reply_key_age_ms),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigReplySurbs> for ReplySurbs {
|
||||
fn from(reply_surbs: ConfigReplySurbs) -> Self {
|
||||
ReplySurbs {
|
||||
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: reply_surbs.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: reply_surbs
|
||||
.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period_ms: reply_surbs
|
||||
.maximum_reply_surb_rerequest_waiting_period
|
||||
.as_millis() as u64,
|
||||
maximum_reply_surb_drop_waiting_period_ms: reply_surbs
|
||||
.maximum_reply_surb_drop_waiting_period
|
||||
.as_millis() as u64,
|
||||
maximum_reply_surb_age_ms: reply_surbs.maximum_reply_surb_age.as_millis() as u64,
|
||||
maximum_reply_key_age_ms: reply_surbs.maximum_reply_key_age.as_millis() as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just a helper structure to more easily pass through the JS boundary
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Debug {
|
||||
/// Defines all configuration options related to traffic streams.
|
||||
pub traffic: Traffic,
|
||||
|
||||
/// Defines all configuration options related to cover traffic stream(s).
|
||||
pub cover_traffic: CoverTraffic,
|
||||
|
||||
/// Defines all configuration options related to the gateway connection.
|
||||
pub gateway_connection: GatewayConnection,
|
||||
|
||||
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
pub acknowledgements: Acknowledgements,
|
||||
|
||||
/// Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
pub topology: Topology,
|
||||
|
||||
/// Defines all configuration options related to reply SURBs.
|
||||
pub reply_surbs: ReplySurbs,
|
||||
}
|
||||
|
||||
impl From<Debug> for ConfigDebug {
|
||||
fn from(debug: Debug) -> Self {
|
||||
// For now we just always use the (older) 32kb extended size
|
||||
let use_extended_packet_size = debug
|
||||
.use_extended_packet_size
|
||||
.then(|| ExtendedPacketSize::Extended32);
|
||||
|
||||
ConfigDebug {
|
||||
traffic: debug.traffic.into(),
|
||||
cover_traffic: debug.cover_traffic.into(),
|
||||
gateway_connection: debug.gateway_connection.into(),
|
||||
acknowledgements: debug.acknowledgements.into(),
|
||||
topology: debug.topology.into(),
|
||||
reply_surbs: debug.reply_surbs.into(),
|
||||
average_packet_delay: Duration::from_millis(debug.average_packet_delay_ms),
|
||||
average_ack_delay: Duration::from_millis(debug.average_ack_delay_ms),
|
||||
ack_wait_multiplier: debug.ack_wait_multiplier,
|
||||
ack_wait_addition: Duration::from_millis(debug.ack_wait_addition_ms),
|
||||
loop_cover_traffic_average_delay: Duration::from_millis(
|
||||
debug.loop_cover_traffic_average_delay_ms,
|
||||
),
|
||||
message_sending_average_delay: Duration::from_millis(
|
||||
debug.message_sending_average_delay_ms,
|
||||
),
|
||||
gateway_response_timeout: Duration::from_millis(debug.gateway_response_timeout_ms),
|
||||
topology_refresh_rate: Duration::from_millis(debug.topology_refresh_rate_ms),
|
||||
topology_resolution_timeout: Duration::from_millis(
|
||||
debug.topology_resolution_timeout_ms,
|
||||
),
|
||||
disable_loop_cover_traffic_stream: debug.disable_loop_cover_traffic_stream,
|
||||
disable_main_poisson_packet_distribution: debug
|
||||
.disable_main_poisson_packet_distribution,
|
||||
use_extended_packet_size,
|
||||
minimum_reply_surb_storage_threshold: debug.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: debug.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: debug.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: debug.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: debug.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period: Duration::from_millis(
|
||||
debug.maximum_reply_surb_rerequest_waiting_period_ms,
|
||||
),
|
||||
maximum_reply_surb_drop_waiting_period: Duration::from_millis(
|
||||
debug.maximum_reply_surb_drop_waiting_period_ms,
|
||||
),
|
||||
maximum_reply_surb_age: Duration::from_millis(debug.maximum_reply_surb_age_ms),
|
||||
maximum_reply_key_age: Duration::from_millis(debug.maximum_reply_key_age_ms),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,12 +187,34 @@ impl From<Debug> for ConfigDebug {
|
||||
impl From<ConfigDebug> for Debug {
|
||||
fn from(debug: ConfigDebug) -> Self {
|
||||
Debug {
|
||||
traffic: debug.traffic.into(),
|
||||
cover_traffic: debug.cover_traffic.into(),
|
||||
gateway_connection: debug.gateway_connection.into(),
|
||||
acknowledgements: debug.acknowledgements.into(),
|
||||
topology: debug.topology.into(),
|
||||
reply_surbs: debug.reply_surbs.into(),
|
||||
average_packet_delay_ms: debug.average_packet_delay.as_millis() as u64,
|
||||
average_ack_delay_ms: debug.average_ack_delay.as_millis() as u64,
|
||||
ack_wait_multiplier: debug.ack_wait_multiplier,
|
||||
ack_wait_addition_ms: debug.ack_wait_addition.as_millis() as u64,
|
||||
loop_cover_traffic_average_delay_ms: debug.loop_cover_traffic_average_delay.as_millis()
|
||||
as u64,
|
||||
message_sending_average_delay_ms: debug.message_sending_average_delay.as_millis()
|
||||
as u64,
|
||||
gateway_response_timeout_ms: debug.gateway_response_timeout.as_millis() as u64,
|
||||
topology_refresh_rate_ms: debug.topology_refresh_rate.as_millis() as u64,
|
||||
topology_resolution_timeout_ms: debug.topology_resolution_timeout.as_millis() as u64,
|
||||
disable_loop_cover_traffic_stream: debug.disable_loop_cover_traffic_stream,
|
||||
disable_main_poisson_packet_distribution: debug
|
||||
.disable_main_poisson_packet_distribution,
|
||||
use_extended_packet_size: debug.use_extended_packet_size.is_some(),
|
||||
minimum_reply_surb_storage_threshold: debug.minimum_reply_surb_storage_threshold,
|
||||
maximum_reply_surb_storage_threshold: debug.maximum_reply_surb_storage_threshold,
|
||||
minimum_reply_surb_request_size: debug.minimum_reply_surb_request_size,
|
||||
maximum_reply_surb_request_size: debug.maximum_reply_surb_request_size,
|
||||
maximum_allowed_reply_surb_request_size: debug.maximum_allowed_reply_surb_request_size,
|
||||
maximum_reply_surb_rerequest_waiting_period_ms: debug
|
||||
.maximum_reply_surb_rerequest_waiting_period
|
||||
.as_millis() as u64,
|
||||
maximum_reply_surb_drop_waiting_period_ms: debug
|
||||
.maximum_reply_surb_drop_waiting_period
|
||||
.as_millis() as u64,
|
||||
maximum_reply_surb_age_ms: debug.maximum_reply_surb_age.as_millis() as u64,
|
||||
maximum_reply_key_age_ms: debug.maximum_reply_key_age.as_millis() as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,14 +82,8 @@ impl NymClientBuilder {
|
||||
// with no persistence
|
||||
fn setup_reply_surb_storage_backend(config: &Config) -> browser_backend::Backend {
|
||||
browser_backend::Backend::new(
|
||||
config
|
||||
.debug
|
||||
.reply_surbs
|
||||
.minimum_reply_surb_storage_threshold,
|
||||
config
|
||||
.debug
|
||||
.reply_surbs
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
config.debug.minimum_reply_surb_storage_threshold,
|
||||
config.debug.maximum_reply_surb_storage_threshold,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-bin-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
description = "Common code for nym binaries"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::coin::Coin;
|
||||
@@ -9,7 +9,6 @@ use crate::nyxd::{Fee, NyxdClient, SigningCosmWasmClient};
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
|
||||
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
||||
use nym_mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
|
||||
@@ -147,16 +146,25 @@ pub trait MixnetSigningClient {
|
||||
// family related
|
||||
async fn create_family(
|
||||
&self,
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::CreateFamily { label }, vec![])
|
||||
.await
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::CreateFamily {
|
||||
owner_signature,
|
||||
label,
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn create_family_on_behalf(
|
||||
&self,
|
||||
owner_address: String,
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
@@ -164,6 +172,7 @@ pub trait MixnetSigningClient {
|
||||
fee,
|
||||
MixnetExecuteMsg::CreateFamilyOnBehalf {
|
||||
owner_address,
|
||||
owner_signature,
|
||||
label,
|
||||
},
|
||||
vec![],
|
||||
@@ -173,14 +182,14 @@ pub trait MixnetSigningClient {
|
||||
|
||||
async fn join_family(
|
||||
&self,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
signature: String,
|
||||
family_head: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::JoinFamily {
|
||||
join_permit,
|
||||
signature,
|
||||
family_head,
|
||||
},
|
||||
vec![],
|
||||
@@ -191,15 +200,17 @@ pub trait MixnetSigningClient {
|
||||
async fn join_family_on_behalf(
|
||||
&self,
|
||||
member_address: String,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_signature: String,
|
||||
family_head: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::JoinFamilyOnBehalf {
|
||||
member_address,
|
||||
join_permit,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head,
|
||||
},
|
||||
vec![],
|
||||
@@ -209,23 +220,33 @@ pub trait MixnetSigningClient {
|
||||
|
||||
async fn leave_family(
|
||||
&self,
|
||||
family_head: FamilyHead,
|
||||
signature: String,
|
||||
family_head: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::LeaveFamily { family_head }, vec![])
|
||||
.await
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::LeaveFamily {
|
||||
signature,
|
||||
family_head,
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn leave_family_on_behalf(
|
||||
&self,
|
||||
member_address: String,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_head: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::LeaveFamilyOnBehalf {
|
||||
member_address,
|
||||
node_identity_signature,
|
||||
family_head,
|
||||
},
|
||||
vec![],
|
||||
@@ -235,16 +256,22 @@ pub trait MixnetSigningClient {
|
||||
|
||||
async fn kick_family_member(
|
||||
&self,
|
||||
signature: String,
|
||||
member: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(fee, MixnetExecuteMsg::KickFamilyMember { member }, vec![])
|
||||
.await
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::KickFamilyMember { signature, member },
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn kick_family_member_on_behalf(
|
||||
&self,
|
||||
head_address: String,
|
||||
signature: String,
|
||||
member: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
@@ -252,6 +279,7 @@ pub trait MixnetSigningClient {
|
||||
fee,
|
||||
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
|
||||
head_address,
|
||||
signature,
|
||||
member,
|
||||
},
|
||||
vec![],
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Coin, Fee, NyxdClient};
|
||||
use async_trait::async_trait;
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
|
||||
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
||||
use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
|
||||
@@ -137,50 +136,6 @@ pub trait VestingSigningClient {
|
||||
cap: Option<PledgeCap>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn vesting_create_family(
|
||||
&self,
|
||||
label: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_vesting_contract(fee, VestingExecuteMsg::CreateFamily { label }, vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_join_family(
|
||||
&self,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_vesting_contract(
|
||||
fee,
|
||||
VestingExecuteMsg::JoinFamily {
|
||||
join_permit,
|
||||
family_head,
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_leave_family(
|
||||
&self,
|
||||
family_head: FamilyHead,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_vesting_contract(fee, VestingExecuteMsg::LeaveFamily { family_head }, vec![])
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_kick_family_member(
|
||||
&self,
|
||||
member: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_vesting_contract(fee, VestingExecuteMsg::KickFamilyMember { member }, vec![])
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -29,7 +29,6 @@ cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegr
|
||||
cosmwasm-std = { workspace = true }
|
||||
|
||||
validator-client = { path = "../client-libs/validator-client", features = ["nyxd-client"] }
|
||||
nym-crypto = { path = "../../common/crypto", features = ["asymmetric"] }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-contracts-common = { path = "../cosmwasm-smart-contracts/contracts-common" }
|
||||
nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use validator_client::nyxd::traits::MixnetSigningClient;
|
||||
use validator_client::nyxd::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Label that is going to be used for creating the family
|
||||
#[arg(long)]
|
||||
pub family_label: String,
|
||||
|
||||
/// Indicates whether the family is going to get created via a vesting account
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn create_family(args: Args, client: SigningClient) {
|
||||
info!("Create family");
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.create_family(args.family_label, None)
|
||||
.await
|
||||
.expect("failed to create family")
|
||||
};
|
||||
|
||||
info!("Family creation result: {:?}", res);
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::QueryClient;
|
||||
use crate::utils::account_id_to_cw_addr;
|
||||
use clap::Parser;
|
||||
use cosmrs::AccountId;
|
||||
use log::info;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::construct_family_join_permit;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use validator_client::nyxd::traits::MixnetQueryClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// Account address (i.e. owner of the family head) which will be used for issuing the permit
|
||||
#[arg(long)]
|
||||
pub address: AccountId,
|
||||
|
||||
/// Indicates whether the member joining the family is going to use the vesting account for joining.
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
// might as well validate the value when parsing the arguments
|
||||
/// Identity of the member for whom we're issuing the permit
|
||||
#[arg(long)]
|
||||
pub member: identity::PublicKey,
|
||||
}
|
||||
|
||||
pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryClient) {
|
||||
info!("Create family join permit sign payload");
|
||||
|
||||
// get the address of our mixnode to recover the family head information
|
||||
let Some(mixnode) = client.get_owned_mixnode(&args.address).await.unwrap().mixnode_details else {
|
||||
eprintln!("{} does not seem to even own a mixnode!", args.address);
|
||||
return
|
||||
};
|
||||
|
||||
// make sure this mixnode is actually a family head
|
||||
if client
|
||||
.get_node_family_by_head(mixnode.bond_information.identity())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_none()
|
||||
{
|
||||
eprintln!("{} does not even seem to own a family!", args.address);
|
||||
return;
|
||||
}
|
||||
|
||||
let nonce = match client.get_signing_nonce(&args.address).await {
|
||||
Ok(nonce) => nonce,
|
||||
Err(err) => {
|
||||
eprint!(
|
||||
"failed to query for the signing nonce of {}: {err}",
|
||||
args.address
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// let address = account_id_to_cw_addr(&args.address);
|
||||
let proxy = if args.with_vesting_account {
|
||||
Some(account_id_to_cw_addr(client.vesting_contract_address()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let head = FamilyHead::new(mixnode.bond_information.identity());
|
||||
|
||||
let payload = construct_family_join_permit(nonce, head, proxy, args.member.to_base58_string());
|
||||
println!("{}", payload.to_base58_string().unwrap())
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use validator_client::nyxd::traits::MixnetSigningClient;
|
||||
use validator_client::nyxd::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// The head of the family that we intend to join
|
||||
#[arg(long)]
|
||||
pub family_head: identity::PublicKey,
|
||||
|
||||
/// Indicates whether the member joining the family is going to do so via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
|
||||
/// Permission, as provided by the family head, for joining the family
|
||||
#[arg(long)]
|
||||
pub join_permit: MessageSignature,
|
||||
}
|
||||
|
||||
pub async fn join_family(args: Args, client: SigningClient) {
|
||||
info!("Join family");
|
||||
|
||||
let family_head = FamilyHead::new(&args.family_head.to_base58_string());
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.join_family(args.join_permit, family_head, None)
|
||||
.await
|
||||
.expect("failed to join family")
|
||||
};
|
||||
|
||||
info!("Family join result: {:?}", res);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use validator_client::nyxd::traits::MixnetSigningClient;
|
||||
use validator_client::nyxd::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// The member of the family that we intend to kick
|
||||
#[arg(long)]
|
||||
pub member: identity::PublicKey,
|
||||
|
||||
/// Indicates whether the family was created (and managed) via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn kick_family_member(args: Args, client: SigningClient) {
|
||||
info!("Leave family");
|
||||
|
||||
let member = args.member.to_base58_string();
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_kick_family_member(member, None)
|
||||
.await
|
||||
.expect("failed to kick family member with vesting account")
|
||||
} else {
|
||||
client
|
||||
.kick_family_member(member, None)
|
||||
.await
|
||||
.expect("failed to kick family member")
|
||||
};
|
||||
|
||||
info!("Family leave result: {:?}", res);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_mixnet_contract_common::families::FamilyHead;
|
||||
use validator_client::nyxd::traits::MixnetSigningClient;
|
||||
use validator_client::nyxd::VestingSigningClient;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
/// The head of the family that we intend to leave
|
||||
#[arg(long)]
|
||||
pub family_head: identity::PublicKey,
|
||||
|
||||
/// Indicates whether we joined the family via the vesting contract
|
||||
#[arg(long)]
|
||||
pub with_vesting_account: bool,
|
||||
}
|
||||
|
||||
pub async fn leave_family(args: Args, client: SigningClient) {
|
||||
info!("Leave family");
|
||||
|
||||
let family_head = FamilyHead::new(&args.family_head.to_base58_string());
|
||||
|
||||
let res = if args.with_vesting_account {
|
||||
client
|
||||
.vesting_leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family with vesting account")
|
||||
} else {
|
||||
client
|
||||
.leave_family(family_head, None)
|
||||
.await
|
||||
.expect("failed to leave family")
|
||||
};
|
||||
|
||||
info!("Family leave result: {:?}", res);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
pub mod create_family;
|
||||
pub mod create_family_join_permit_sign_payload;
|
||||
pub mod join_family;
|
||||
pub mod kick_family_member;
|
||||
pub mod leave_family;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
|
||||
pub struct MixnetOperatorsMixnodeFamilies {
|
||||
#[clap(subcommand)]
|
||||
pub command: MixnetOperatorsMixnodeFamiliesCommands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum MixnetOperatorsMixnodeFamiliesCommands {
|
||||
/// Create family
|
||||
CreateFamily(create_family::Args),
|
||||
|
||||
/// Join family
|
||||
JoinFamily(join_family::Args),
|
||||
|
||||
/// Leave family,
|
||||
LeaveFamily(leave_family::Args),
|
||||
|
||||
/// Kick family member
|
||||
KickFamilyMember(kick_family_member::Args),
|
||||
|
||||
/// Create a message payload that is required to get signed in order to obtain a permit for joining family
|
||||
CreateFamilyJoinPermitSignPayload(create_family_join_permit_sign_payload::Args),
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
pub mod bond_mixnode;
|
||||
pub mod families;
|
||||
pub mod keys;
|
||||
pub mod mixnode_bonding_sign_payload;
|
||||
pub mod rewards;
|
||||
@@ -28,8 +27,6 @@ pub enum MixnetOperatorsMixnodeCommands {
|
||||
Rewards(rewards::MixnetOperatorsMixnodeRewards),
|
||||
/// Manage your mixnode settings stored in the directory
|
||||
Settings(settings::MixnetOperatorsMixnodeSettings),
|
||||
/// Operations for mixnode families
|
||||
Families(families::MixnetOperatorsMixnodeFamilies),
|
||||
/// Bond to a mixnode
|
||||
Bond(bond_mixnode::Args),
|
||||
/// Unbond from a mixnode
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-contracts-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
description = "Common library for Nym cosmwasm contracts"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-mixnet-contract-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
description = "Common library for the Nym mixnet contract"
|
||||
rust-version = "1.62"
|
||||
edition = { workspace = true }
|
||||
@@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
schemars = "0.8"
|
||||
thiserror = "1.0"
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.3.0" }
|
||||
# use 0.4.1 as that's the version used by cosmwasm-std 1.0.0
|
||||
# (and ideally we don't want to pull the same dependency twice)
|
||||
serde-json-wasm = "=0.4.1"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use crate::{IdentityKey, IdentityKeyRef};
|
||||
use cosmwasm_std::Addr;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
@@ -22,45 +20,9 @@ pub struct Family {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/NodeFamilyHead.ts")
|
||||
)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, JsonSchema)]
|
||||
pub struct FamilyHead(IdentityKey);
|
||||
|
||||
impl Serialize for FamilyHead {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FamilyHead {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let inner = IdentityKey::deserialize(deserializer)?;
|
||||
Ok(FamilyHead(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for FamilyHead {
|
||||
type Err = <IdentityKey as FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// theoretically we should be verifying whether it's a valid base58 value
|
||||
// (or even better, whether it's a valid ed25519 public key), but definition of
|
||||
// `FamilyHead` might change later
|
||||
Ok(FamilyHead(IdentityKey::from_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FamilyHead {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FamilyHead {
|
||||
pub fn new(identity: IdentityKeyRef<'_>) -> Self {
|
||||
FamilyHead(identity.to_string())
|
||||
@@ -72,11 +34,11 @@ impl FamilyHead {
|
||||
}
|
||||
|
||||
impl Family {
|
||||
pub fn new(head: FamilyHead, proxy: Option<Addr>, label: String) -> Self {
|
||||
pub fn new(head: FamilyHead, proxy: Option<Addr>, label: &str) -> Self {
|
||||
Family {
|
||||
head,
|
||||
proxy: proxy.map(|p| p.to_string()),
|
||||
label,
|
||||
label: label.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,21 +60,3 @@ impl Family {
|
||||
&self.label
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn family_head_serde() {
|
||||
let dummy = FamilyHead::new("foomp");
|
||||
|
||||
let ser_str = serde_json_wasm::to_string(&dummy).unwrap();
|
||||
let de_str: FamilyHead = serde_json_wasm::from_str(&ser_str).unwrap();
|
||||
assert_eq!(dummy, de_str);
|
||||
|
||||
let ser_bytes = serde_json_wasm::to_vec(&dummy).unwrap();
|
||||
let de_bytes: FamilyHead = serde_json_wasm::from_slice(&ser_bytes).unwrap();
|
||||
assert_eq!(dummy, de_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crate::delegation::OwnerProxySubKey;
|
||||
use crate::error::MixnetContractError;
|
||||
use crate::families::FamilyHead;
|
||||
use crate::gateway::GatewayConfigUpdate;
|
||||
use crate::helpers::IntoBaseDecimal;
|
||||
use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
||||
@@ -83,35 +82,42 @@ pub enum ExecuteMsg {
|
||||
// Families
|
||||
/// Only owner of the node can crate the family with node as head
|
||||
CreateFamily {
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
},
|
||||
/// Family head needs to sign the joining node IdentityKey
|
||||
JoinFamily {
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
signature: String,
|
||||
family_head: IdentityKey,
|
||||
},
|
||||
LeaveFamily {
|
||||
family_head: FamilyHead,
|
||||
signature: String,
|
||||
family_head: IdentityKey,
|
||||
},
|
||||
KickFamilyMember {
|
||||
signature: String,
|
||||
member: IdentityKey,
|
||||
},
|
||||
CreateFamilyOnBehalf {
|
||||
owner_address: String,
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
},
|
||||
/// Family head needs to sign the joining node IdentityKey, MixNode needs to provide its signature proving that it wants to join the family
|
||||
JoinFamilyOnBehalf {
|
||||
member_address: String,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_signature: String,
|
||||
family_head: IdentityKey,
|
||||
},
|
||||
LeaveFamilyOnBehalf {
|
||||
member_address: String,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_head: IdentityKey,
|
||||
},
|
||||
KickFamilyMemberOnBehalf {
|
||||
head_address: String,
|
||||
signature: String,
|
||||
member: IdentityKey,
|
||||
},
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::families::FamilyHead;
|
||||
use crate::{Gateway, IdentityKey, MixNode, MixNodeCostParams};
|
||||
use crate::{Gateway, MixNode, MixNodeCostParams};
|
||||
use contracts_common::signing::{
|
||||
ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose,
|
||||
};
|
||||
@@ -11,7 +10,6 @@ use serde::Serialize;
|
||||
|
||||
pub type SignableMixNodeBondingMsg = SignableMessage<ContractMessageContent<MixnodeBondingPayload>>;
|
||||
pub type SignableGatewayBondingMsg = SignableMessage<ContractMessageContent<GatewayBondingPayload>>;
|
||||
pub type SignableFamilyJoinPermitMsg = SignableMessage<FamilyJoinPermit>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct MixnodeBondingPayload {
|
||||
@@ -79,43 +77,75 @@ pub fn construct_gateway_bonding_sign_payload(
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FamilyJoinPermit {
|
||||
// the granter of this permit
|
||||
family_head: FamilyHead,
|
||||
// whether the **member** will want to join via the proxy (i.e. vesting contract)
|
||||
proxy: Option<Addr>,
|
||||
// the actual member we want to permit to join
|
||||
member_node: IdentityKey,
|
||||
pub struct FamilyCreationSignature {
|
||||
label: String,
|
||||
// TODO: add any extra fields?
|
||||
}
|
||||
|
||||
impl FamilyJoinPermit {
|
||||
pub fn new(family_head: FamilyHead, proxy: Option<Addr>, member_node: IdentityKey) -> Self {
|
||||
Self {
|
||||
family_head,
|
||||
proxy,
|
||||
member_node,
|
||||
}
|
||||
impl FamilyCreationSignature {
|
||||
pub fn new(label: String) -> Self {
|
||||
Self { label }
|
||||
}
|
||||
}
|
||||
|
||||
impl SigningPurpose for FamilyJoinPermit {
|
||||
impl SigningPurpose for FamilyCreationSignature {
|
||||
fn message_type() -> MessageType {
|
||||
MessageType::new("family-join-permit")
|
||||
MessageType::new("family-creation")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_family_join_permit(
|
||||
nonce: Nonce,
|
||||
family_head: FamilyHead,
|
||||
proxy: Option<Addr>,
|
||||
member_node: IdentityKey,
|
||||
) -> SignableFamilyJoinPermitMsg {
|
||||
let payload = FamilyJoinPermit::new(family_head, proxy, member_node);
|
||||
#[derive(Serialize)]
|
||||
pub struct FamilyJoinSignature {
|
||||
family_head: String,
|
||||
// TODO: add any extra fields?
|
||||
}
|
||||
|
||||
// note: we're NOT wrapping it in `ContractMessageContent` because the family head is not going to be the one
|
||||
// sending the message to the contract
|
||||
SignableMessage::new(nonce, payload)
|
||||
impl FamilyJoinSignature {
|
||||
pub fn new(family_head: String) -> Self {
|
||||
Self { family_head }
|
||||
}
|
||||
}
|
||||
|
||||
impl SigningPurpose for FamilyJoinSignature {
|
||||
fn message_type() -> MessageType {
|
||||
MessageType::new("family-join")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FamilyLeaveSignature {
|
||||
family_head: String,
|
||||
// TODO: add any extra fields?
|
||||
}
|
||||
|
||||
impl FamilyLeaveSignature {
|
||||
pub fn new(family_head: String) -> Self {
|
||||
Self { family_head }
|
||||
}
|
||||
}
|
||||
|
||||
impl SigningPurpose for FamilyLeaveSignature {
|
||||
fn message_type() -> MessageType {
|
||||
MessageType::new("family-leave")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FamilyKickSignature {
|
||||
member: String,
|
||||
// TODO: add any extra fields?
|
||||
}
|
||||
|
||||
impl FamilyKickSignature {
|
||||
pub fn new(member: String) -> Self {
|
||||
Self { member }
|
||||
}
|
||||
}
|
||||
|
||||
impl SigningPurpose for FamilyKickSignature {
|
||||
fn message_type() -> MessageType {
|
||||
MessageType::new("family-member-removal")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: depending on our threat model, we should perhaps extend it to include all _on_behalf methods
|
||||
// (update: but we trust our vesting contract since its compromise would be even more devastating so there's no need)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-vesting-contract-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
description = "Common library for the Nym vesting contract"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -9,8 +9,8 @@ repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-std = { workspace = true }
|
||||
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.4.0" }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
||||
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.3.0" }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.3.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
schemars = "0.8"
|
||||
ts-rs = {version = "6.1.2", optional = true}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use contracts_common::signing::MessageSignature;
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use mixnet_contract_common::families::FamilyHead;
|
||||
use mixnet_contract_common::{
|
||||
gateway::GatewayConfigUpdate,
|
||||
mixnode::{MixNodeConfigUpdate, MixNodeCostParams},
|
||||
@@ -61,17 +60,21 @@ pub enum ExecuteMsg {
|
||||
// Families
|
||||
/// Only owner of the node can crate the family with node as head
|
||||
CreateFamily {
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
},
|
||||
/// Family head needs to sign the joining node IdentityKey, the Node provides its signature signaling consent to join the family
|
||||
JoinFamily {
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_signature: String,
|
||||
family_head: IdentityKey,
|
||||
},
|
||||
LeaveFamily {
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_head: IdentityKey,
|
||||
},
|
||||
KickFamilyMember {
|
||||
signature: String,
|
||||
member: IdentityKey,
|
||||
},
|
||||
TrackReward {
|
||||
|
||||
@@ -48,12 +48,12 @@ impl CoconutCredentialManager {
|
||||
/// Tries to retrieve one of the stored, unused credentials.
|
||||
pub(crate) async fn get_next_coconut_credential(
|
||||
&self,
|
||||
) -> Result<CoconutCredential, sqlx::Error> {
|
||||
) -> Result<Option<CoconutCredential>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
CoconutCredential,
|
||||
"SELECT * FROM coconut_credentials WHERE NOT consumed"
|
||||
)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -13,4 +13,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("Inconsistent data in database")]
|
||||
InconsistentData,
|
||||
|
||||
#[error("No unused credential in database. You need to buy at least one")]
|
||||
NoCredential,
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@ impl Storage for PersistentStorage {
|
||||
let credential = self
|
||||
.coconut_credential_manager
|
||||
.get_next_coconut_credential()
|
||||
.await?;
|
||||
.await?
|
||||
.ok_or(StorageError::NoCredential)?;
|
||||
|
||||
Ok(credential)
|
||||
}
|
||||
|
||||
@@ -99,24 +99,17 @@ impl ConnectionHandler {
|
||||
let mut framed_conn = Framed::new(conn, EchoPacketCodec);
|
||||
while !shutdown_listener.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown_listener.recv() => {
|
||||
trace!("ConnectionHandler: Shutdown received");
|
||||
}
|
||||
maybe_echo_packet = framed_conn.next() => {
|
||||
Some(echo_packet) = framed_conn.next() => {
|
||||
// handle echo packet
|
||||
let reply_packet = match maybe_echo_packet {
|
||||
Some(Ok(echo_packet)) => self.handle_echo_packet(echo_packet),
|
||||
Some(Err(err)) => {
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {err}. Closing the socket",
|
||||
let reply_packet = match echo_packet {
|
||||
Ok(echo_packet) => self.handle_echo_packet(echo_packet),
|
||||
Err(err) => {
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {}. Closing the socket",
|
||||
err
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
error!("The socket connection got terminated by the remote!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// write back the reply (note the lack of framing)
|
||||
@@ -132,6 +125,9 @@ impl ConnectionHandler {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
trace!("ConnectionHandler: Shutdown received");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ impl MessageReceiver for OutfoxMessageReceiver {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn reconstructor(&mut self) -> &mut MessageReconstructor {
|
||||
&mut self.reconstructor
|
||||
fn reconstructor(&self) -> MessageReconstructor {
|
||||
self.reconstructor.clone()
|
||||
}
|
||||
|
||||
fn num_mix_hops(&self) -> u8 {
|
||||
@@ -123,7 +123,7 @@ impl MessageReceiver for OutfoxMessageReceiver {
|
||||
|
||||
pub trait MessageReceiver {
|
||||
fn new() -> Self;
|
||||
fn reconstructor(&mut self) -> &mut MessageReconstructor;
|
||||
fn reconstructor(&self) -> MessageReconstructor;
|
||||
fn num_mix_hops(&self) -> u8;
|
||||
|
||||
fn decrypt_raw_message<C>(
|
||||
@@ -239,8 +239,8 @@ impl MessageReceiver for SphinxMessageReceiver {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reconstructor(&mut self) -> &mut MessageReconstructor {
|
||||
&mut self.reconstructor
|
||||
fn reconstructor(&self) -> MessageReconstructor {
|
||||
self.reconstructor.clone()
|
||||
}
|
||||
|
||||
fn num_mix_hops(&self) -> u8 {
|
||||
|
||||
@@ -2,15 +2,6 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [v1.1.5] (2023-04-04)
|
||||
- change in-contract signatures to include nonces and to sign entire payloads for family-related operations ([#3125])
|
||||
- change in-contract signatures to include nonces and to sign entire payloads for node bonding (will require wallet changes) ([#3067])
|
||||
- removed migration code from mixnet and vesting contracts ([#3207])
|
||||
|
||||
[#3125]: https://github.com/nymtech/nym/issues/3125
|
||||
[#3067]: https://github.com/nymtech/nym/issues/3067
|
||||
[#3207]: https://github.com/nymtech/nym/pull/3207
|
||||
|
||||
## [v1.1.4] (2023-02-21)
|
||||
|
||||
- Problem 142 (rust-side) ([#3024])
|
||||
|
||||
Generated
+5
-5
@@ -1018,7 +1018,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-contracts-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"cosmwasm-std",
|
||||
@@ -1052,7 +1052,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnet-contract"
|
||||
version = "1.3.0"
|
||||
version = "1.2.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"cosmwasm-derive",
|
||||
@@ -1076,7 +1076,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnet-contract-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"cosmwasm-std",
|
||||
@@ -1121,7 +1121,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-vesting-contract"
|
||||
version = "1.3.0"
|
||||
version = "1.2.0"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"cosmwasm-crypto",
|
||||
@@ -1144,7 +1144,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-vesting-contract-common"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"nym-contracts-common",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-mixnet-contract"
|
||||
version = "1.3.0"
|
||||
version = "1.2.0"
|
||||
description = "Nym mixnet contract"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -22,9 +22,9 @@ name = "mixnet_contract"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.4.0" }
|
||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.4.0" }
|
||||
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.4.0" }
|
||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.3.0" }
|
||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.3.0" }
|
||||
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.3.0" }
|
||||
|
||||
cosmwasm-std = { workspace = true }
|
||||
cosmwasm-storage = { workspace = true }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
opt: wasm
|
||||
wasm-opt --disable-sign-ext -Os ../target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o ../target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
wasm-opt -Os ../target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o ../target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
|
||||
wasm:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::mixnodes::storage as mixnode_storage;
|
||||
use crate::rewards::storage as rewards_storage;
|
||||
use cosmwasm_std::{
|
||||
entry_point, to_binary, Addr, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
|
||||
StdError,
|
||||
};
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::{
|
||||
@@ -104,56 +105,68 @@ pub fn execute(
|
||||
crate::mixnodes::transactions::assign_mixnode_layer(deps, info, mix_id, layer)
|
||||
}
|
||||
// families
|
||||
ExecuteMsg::CreateFamily { label } => {
|
||||
crate::families::transactions::try_create_family(deps, info, label)
|
||||
}
|
||||
ExecuteMsg::CreateFamily {
|
||||
owner_signature,
|
||||
label,
|
||||
} => crate::families::transactions::try_create_family(deps, info, owner_signature, &label),
|
||||
ExecuteMsg::JoinFamily {
|
||||
join_permit,
|
||||
signature,
|
||||
family_head,
|
||||
} => crate::families::transactions::try_join_family(deps, info, join_permit, family_head),
|
||||
ExecuteMsg::LeaveFamily { family_head } => {
|
||||
crate::families::transactions::try_leave_family(deps, info, family_head)
|
||||
} => {
|
||||
crate::families::transactions::try_join_family(deps, info, None, signature, family_head)
|
||||
}
|
||||
ExecuteMsg::KickFamilyMember { member } => {
|
||||
crate::families::transactions::try_head_kick_member(deps, info, member)
|
||||
ExecuteMsg::LeaveFamily {
|
||||
signature,
|
||||
family_head,
|
||||
} => crate::families::transactions::try_leave_family(deps, info, signature, family_head),
|
||||
ExecuteMsg::KickFamilyMember { signature, member } => {
|
||||
crate::families::transactions::try_head_kick_member(deps, info, signature, &member)
|
||||
}
|
||||
ExecuteMsg::CreateFamilyOnBehalf {
|
||||
owner_address,
|
||||
owner_signature,
|
||||
label,
|
||||
} => crate::families::transactions::try_create_family_on_behalf(
|
||||
deps,
|
||||
info,
|
||||
owner_address,
|
||||
label,
|
||||
owner_signature,
|
||||
&label,
|
||||
),
|
||||
ExecuteMsg::JoinFamilyOnBehalf {
|
||||
member_address,
|
||||
join_permit,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head,
|
||||
} => crate::families::transactions::try_join_family_on_behalf(
|
||||
deps,
|
||||
info,
|
||||
member_address,
|
||||
join_permit,
|
||||
Some(node_identity_signature),
|
||||
family_signature,
|
||||
family_head,
|
||||
),
|
||||
ExecuteMsg::LeaveFamilyOnBehalf {
|
||||
member_address,
|
||||
node_identity_signature,
|
||||
family_head,
|
||||
} => crate::families::transactions::try_leave_family_on_behalf(
|
||||
deps,
|
||||
info,
|
||||
member_address,
|
||||
node_identity_signature,
|
||||
family_head,
|
||||
),
|
||||
ExecuteMsg::KickFamilyMemberOnBehalf {
|
||||
head_address,
|
||||
signature,
|
||||
member,
|
||||
} => crate::families::transactions::try_head_kick_member_on_behalf(
|
||||
deps,
|
||||
info,
|
||||
head_address,
|
||||
member,
|
||||
signature,
|
||||
&member,
|
||||
),
|
||||
// state/sys-params-related
|
||||
ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
|
||||
@@ -380,13 +393,13 @@ pub fn query(
|
||||
&crate::families::queries::get_family_by_head(&head, deps.storage)?,
|
||||
),
|
||||
QueryMsg::GetFamilyByLabel { label } => to_binary(
|
||||
&crate::families::queries::get_family_by_label(label, deps.storage)?,
|
||||
&crate::families::queries::get_family_by_label(&label, deps.storage)?,
|
||||
),
|
||||
QueryMsg::GetFamilyMembersByHead { head } => to_binary(
|
||||
&crate::families::queries::get_family_members_by_head(&head, deps.storage)?,
|
||||
),
|
||||
QueryMsg::GetFamilyMembersByLabel { label } => to_binary(
|
||||
&crate::families::queries::get_family_members_by_label(label, deps.storage)?,
|
||||
&crate::families::queries::get_family_members_by_label(&label, deps.storage)?,
|
||||
),
|
||||
QueryMsg::GetContractVersion {} => {
|
||||
to_binary(&crate::mixnet_contract_settings::queries::query_contract_version())
|
||||
@@ -590,6 +603,17 @@ pub fn migrate(
|
||||
_env: Env,
|
||||
msg: MigrateMsg,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
// this is the first migration that uses cw2 standard and thus the value in the storage doesn't yet exist
|
||||
// set it instead.
|
||||
if matches!(
|
||||
cw2::get_contract_version(deps.storage),
|
||||
Err(StdError::NotFound { .. })
|
||||
) {
|
||||
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
crate::queued_migrations::create_epoch_status(deps.storage)?;
|
||||
return Ok(Response::new());
|
||||
}
|
||||
|
||||
// note: don't remove this particular bit of code as we have to ALWAYS check whether we have to update the stored version
|
||||
let version: Version = CONTRACT_VERSION.parse().map_err(|error: semver::Error| {
|
||||
MixnetContractError::SemVerFailure {
|
||||
@@ -611,7 +635,8 @@ pub fn migrate(
|
||||
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
|
||||
// If state structure changed in any contract version in the way migration is needed, it
|
||||
// should occur here, for example anything from `crate::queued_migrations::`
|
||||
// should occur here
|
||||
crate::queued_migrations::create_epoch_status(deps.storage)?;
|
||||
}
|
||||
|
||||
// due to circular dependency on contract addresses (i.e. mixnet contract requiring vesting contract address
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod queries;
|
||||
pub mod signature_helpers;
|
||||
pub mod storage;
|
||||
pub mod transactions;
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::constants::{FAMILIES_DEFAULT_RETRIEVAL_LIMIT, FAMILIES_MAX_RETRIEVAL_LIMIT};
|
||||
|
||||
use super::storage::{families, get_family, get_members, MEMBERS};
|
||||
use crate::constants::{FAMILIES_DEFAULT_RETRIEVAL_LIMIT, FAMILIES_MAX_RETRIEVAL_LIMIT};
|
||||
use cosmwasm_std::{Order, Storage};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::families::{Family, FamilyHead};
|
||||
use mixnet_contract_common::{error::MixnetContractError, IdentityKeyRef};
|
||||
use mixnet_contract_common::{IdentityKey, PagedFamiliesResponse, PagedMembersResponse};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn get_family_by_label(
|
||||
label: String,
|
||||
label: &str,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<Family>, MixnetContractError> {
|
||||
Ok(families().idx.label.item(storage, label)?.map(|o| o.1))
|
||||
Ok(families()
|
||||
.idx
|
||||
.label
|
||||
.item(storage, label.to_string())?
|
||||
.map(|o| o.1))
|
||||
}
|
||||
|
||||
pub fn get_family_by_head(
|
||||
head: IdentityKeyRef<'_>,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<Family>, MixnetContractError> {
|
||||
Ok(families().may_load(storage, head.to_string())?)
|
||||
) -> Result<Family, MixnetContractError> {
|
||||
let family_head = FamilyHead::new(head);
|
||||
get_family(&family_head, storage)
|
||||
}
|
||||
|
||||
pub fn get_family_members_by_head(
|
||||
@@ -34,10 +38,15 @@ pub fn get_family_members_by_head(
|
||||
}
|
||||
|
||||
pub fn get_family_members_by_label(
|
||||
label: String,
|
||||
label: &str,
|
||||
storage: &dyn Storage,
|
||||
) -> Result<Option<HashSet<String>>, MixnetContractError> {
|
||||
if let Some(family) = families().idx.label.item(storage, label)?.map(|o| o.1) {
|
||||
if let Some(family) = families()
|
||||
.idx
|
||||
.label
|
||||
.item(storage, label.to_string())?
|
||||
.map(|o| o.1)
|
||||
{
|
||||
Ok(Some(get_members(&family, storage)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use crate::signing::storage as signing_storage;
|
||||
use crate::support::helpers::decode_ed25519_identity_key;
|
||||
use cosmwasm_std::{Addr, Deps};
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::families::FamilyHead;
|
||||
use mixnet_contract_common::{construct_family_join_permit, IdentityKeyRef};
|
||||
use nym_contracts_common::signing::{MessageSignature, Verifier};
|
||||
|
||||
pub(crate) fn verify_family_join_permit(
|
||||
deps: Deps<'_>,
|
||||
granter: FamilyHead,
|
||||
proxy: Option<Addr>,
|
||||
member: IdentityKeyRef,
|
||||
signature: MessageSignature,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
// recover the public key
|
||||
let public_key = decode_ed25519_identity_key(granter.identity())?;
|
||||
|
||||
// that's kinda a backwards way of getting the granter's nonce, but it works, so ¯\_(ツ)_/¯
|
||||
let Some(head_mixnode) = mixnodes_storage::mixnode_bonds()
|
||||
.idx
|
||||
.identity_key
|
||||
.item(deps.storage, granter.identity().to_owned())?.map(|record| record.1) else {
|
||||
return Err(MixnetContractError::FamilyDoesNotExist { head: granter.identity().to_string() })
|
||||
};
|
||||
let nonce = signing_storage::get_signing_nonce(deps.storage, head_mixnode.owner)?;
|
||||
let msg = construct_family_join_permit(nonce, granter, proxy, member.to_owned());
|
||||
|
||||
if deps.api.verify_message(msg, signature, &public_key)? {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(MixnetContractError::InvalidEd25519Signature)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use std::collections::HashSet;
|
||||
|
||||
use cosmwasm_std::{Order, Storage};
|
||||
use cosmwasm_std::{Order, StdError, Storage};
|
||||
use cw_storage_plus::{Index, IndexList, IndexedMap, Map, UniqueIndex};
|
||||
use mixnet_contract_common::families::{Family, FamilyHead};
|
||||
use mixnet_contract_common::{error::MixnetContractError, IdentityKey, IdentityKeyRef};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::constants::{FAMILIES_INDEX_NAMESPACE, FAMILIES_MAP_NAMESPACE, MEMBERS_MAP_NAMESPACE};
|
||||
|
||||
@@ -53,8 +51,22 @@ pub fn get_family(head: &FamilyHead, store: &dyn Storage) -> Result<Family, Mixn
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_family(f: &Family, store: &mut dyn Storage) -> Result<(), MixnetContractError> {
|
||||
Ok(families().save(store, f.head_identity().to_string(), f)?)
|
||||
pub fn create_family(f: &Family, store: &mut dyn Storage) -> Result<(), MixnetContractError> {
|
||||
match families().save(store, f.head_identity().to_string(), f) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => match &e {
|
||||
StdError::GenericErr { msg } => {
|
||||
if msg.starts_with("Violates unique constraint") {
|
||||
Err(MixnetContractError::FamilyWithLabelExists(
|
||||
f.label().to_string(),
|
||||
))
|
||||
} else {
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
_ => Err(e.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_family_member(
|
||||
|
||||
@@ -1,99 +1,136 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage::{
|
||||
add_family_member, get_family, is_any_member, is_family_member, remove_family_member,
|
||||
save_family,
|
||||
use crate::support::helpers::{
|
||||
ensure_bonded, ensure_sent_by_vesting_contract, validate_family_signature,
|
||||
validate_node_identity_signature,
|
||||
};
|
||||
use crate::families::queries::get_family_by_label;
|
||||
use crate::families::signature_helpers::verify_family_join_permit;
|
||||
use crate::support::helpers::{ensure_bonded, ensure_sent_by_vesting_contract};
|
||||
|
||||
use cosmwasm_std::{Addr, DepsMut, MessageInfo, Response};
|
||||
use mixnet_contract_common::families::{Family, FamilyHead};
|
||||
use mixnet_contract_common::{error::MixnetContractError, IdentityKey};
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
use mixnet_contract_common::{error::MixnetContractError, IdentityKey, IdentityKeyRef};
|
||||
|
||||
use super::storage::{
|
||||
add_family_member, create_family, get_family, is_any_member, is_family_member,
|
||||
remove_family_member,
|
||||
};
|
||||
|
||||
/// Creates a new MixNode family with senders node as head
|
||||
pub fn try_create_family(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
label: String,
|
||||
owner_signature: String,
|
||||
label: &str,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
_try_create_family(deps, &info.sender, label, None)
|
||||
_try_create_family(deps, &info.sender, owner_signature, label, None)
|
||||
}
|
||||
|
||||
pub fn try_create_family_on_behalf(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
owner_address: String,
|
||||
label: String,
|
||||
owner_signature: String,
|
||||
label: &str,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
ensure_sent_by_vesting_contract(&info, deps.storage)?;
|
||||
|
||||
let owner_address = deps.api.addr_validate(&owner_address)?;
|
||||
_try_create_family(deps, &owner_address, label, Some(info.sender))
|
||||
_try_create_family(
|
||||
deps,
|
||||
&owner_address,
|
||||
owner_signature,
|
||||
label,
|
||||
Some(info.sender),
|
||||
)
|
||||
}
|
||||
|
||||
fn _try_create_family(
|
||||
deps: DepsMut,
|
||||
owner: &Addr,
|
||||
label: String,
|
||||
owner_signature: String,
|
||||
label: &str,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
let existing_bond =
|
||||
crate::mixnodes::helpers::must_get_mixnode_bond_by_owner(deps.storage, owner)?;
|
||||
let existing_bond = crate::mixnodes::storage::mixnode_bonds()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.storage, owner.clone())?
|
||||
.ok_or(MixnetContractError::NoAssociatedMixNodeBond {
|
||||
owner: owner.clone(),
|
||||
})?
|
||||
.1;
|
||||
|
||||
ensure_bonded(&existing_bond)?;
|
||||
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
owner,
|
||||
&owner_signature,
|
||||
existing_bond.identity(),
|
||||
)?;
|
||||
|
||||
let family_head = FamilyHead::new(existing_bond.identity());
|
||||
|
||||
// can't overwrite existing family
|
||||
if get_family(&family_head, deps.storage).is_ok() {
|
||||
if let Ok(_family) = get_family(&family_head, deps.storage) {
|
||||
return Err(MixnetContractError::FamilyCanHaveOnlyOne);
|
||||
}
|
||||
|
||||
// the label must be unique
|
||||
if get_family_by_label(label.clone(), deps.storage)?.is_some() {
|
||||
return Err(MixnetContractError::FamilyWithLabelExists(label));
|
||||
}
|
||||
|
||||
let family = Family::new(family_head, proxy, label);
|
||||
save_family(&family, deps.storage)?;
|
||||
create_family(&family, deps.storage)?;
|
||||
Ok(Response::default())
|
||||
}
|
||||
|
||||
pub fn try_join_family(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
// Required for proxy joining
|
||||
node_identity_signature: Option<String>,
|
||||
family_signature: String,
|
||||
family_head: IdentityKey,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
_try_join_family(deps, &info.sender, join_permit, family_head, None)
|
||||
let family_head = FamilyHead::new(&family_head);
|
||||
_try_join_family(
|
||||
deps,
|
||||
&info.sender,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_join_family_on_behalf(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
member_address: String,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: Option<String>,
|
||||
family_signature: String,
|
||||
family_head: IdentityKey,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
ensure_sent_by_vesting_contract(&info, deps.storage)?;
|
||||
|
||||
let member_address = deps.api.addr_validate(&member_address)?;
|
||||
let proxy = Some(info.sender);
|
||||
_try_join_family(deps, &member_address, join_permit, family_head, proxy)
|
||||
let family_head = FamilyHead::new(&family_head);
|
||||
_try_join_family(
|
||||
deps,
|
||||
&member_address,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head,
|
||||
)
|
||||
}
|
||||
|
||||
fn _try_join_family(
|
||||
deps: DepsMut,
|
||||
owner: &Addr,
|
||||
join_permit: MessageSignature,
|
||||
node_identity_signature: Option<String>,
|
||||
family_signature: String,
|
||||
family_head: FamilyHead,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
let existing_bond =
|
||||
crate::mixnodes::helpers::must_get_mixnode_bond_by_owner(deps.storage, owner)?;
|
||||
let existing_bond = crate::mixnodes::storage::mixnode_bonds()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.storage, owner.clone())?
|
||||
.ok_or(MixnetContractError::NoAssociatedMixNodeBond {
|
||||
owner: owner.clone(),
|
||||
})?
|
||||
.1;
|
||||
|
||||
ensure_bonded(&existing_bond)?;
|
||||
|
||||
@@ -110,12 +147,20 @@ fn _try_join_family(
|
||||
));
|
||||
}
|
||||
|
||||
verify_family_join_permit(
|
||||
if let Some(node_identity_signature) = node_identity_signature {
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
owner,
|
||||
&node_identity_signature,
|
||||
existing_bond.identity(),
|
||||
)?;
|
||||
}
|
||||
|
||||
validate_family_signature(
|
||||
deps.as_ref(),
|
||||
family_head.clone(),
|
||||
proxy,
|
||||
existing_bond.identity(),
|
||||
join_permit,
|
||||
&family_signature,
|
||||
family_head.identity(),
|
||||
)?;
|
||||
|
||||
let family = get_family(&family_head, deps.storage)?;
|
||||
@@ -128,30 +173,41 @@ fn _try_join_family(
|
||||
pub fn try_leave_family(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
family_head: FamilyHead,
|
||||
signature: String,
|
||||
family_head: IdentityKey,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
_try_leave_family(deps, &info.sender, family_head)
|
||||
let family_head = FamilyHead::new(&family_head);
|
||||
_try_leave_family(deps, &info.sender, signature, family_head)
|
||||
}
|
||||
|
||||
pub fn try_leave_family_on_behalf(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
member_address: String,
|
||||
family_head: FamilyHead,
|
||||
node_family_signature: String,
|
||||
family_head: IdentityKey,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
ensure_sent_by_vesting_contract(&info, deps.storage)?;
|
||||
|
||||
let family_head = FamilyHead::new(&family_head);
|
||||
let member_address = deps.api.addr_validate(&member_address)?;
|
||||
_try_leave_family(deps, &member_address, family_head)
|
||||
_try_leave_family(deps, &member_address, node_family_signature, family_head)
|
||||
}
|
||||
|
||||
fn _try_leave_family(
|
||||
deps: DepsMut,
|
||||
owner: &Addr,
|
||||
node_family_signature: String,
|
||||
family_head: FamilyHead,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
let existing_bond =
|
||||
crate::mixnodes::helpers::must_get_mixnode_bond_by_owner(deps.storage, owner)?;
|
||||
let existing_bond = crate::mixnodes::storage::mixnode_bonds()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.storage, owner.clone())?
|
||||
.ok_or(MixnetContractError::NoAssociatedMixNodeBond {
|
||||
owner: owner.clone(),
|
||||
})?
|
||||
.1;
|
||||
|
||||
ensure_bonded(&existing_bond)?;
|
||||
|
||||
@@ -170,6 +226,13 @@ fn _try_leave_family(
|
||||
});
|
||||
}
|
||||
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
owner,
|
||||
&node_family_signature,
|
||||
existing_bond.identity(),
|
||||
)?;
|
||||
|
||||
remove_family_member(deps.storage, existing_bond.identity());
|
||||
|
||||
Ok(Response::default())
|
||||
@@ -178,56 +241,62 @@ fn _try_leave_family(
|
||||
pub fn try_head_kick_member(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
member: IdentityKey,
|
||||
owner_signature: String,
|
||||
member: IdentityKeyRef,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
_try_head_kick_member(deps, &info.sender, member)
|
||||
_try_head_kick_member(deps, &info.sender, owner_signature, member)
|
||||
}
|
||||
|
||||
pub fn try_head_kick_member_on_behalf(
|
||||
deps: DepsMut,
|
||||
info: MessageInfo,
|
||||
head_address: String,
|
||||
member: IdentityKey,
|
||||
owner_signature: String,
|
||||
member: IdentityKeyRef,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
ensure_sent_by_vesting_contract(&info, deps.storage)?;
|
||||
|
||||
let head_address = deps.api.addr_validate(&head_address)?;
|
||||
_try_head_kick_member(deps, &head_address, member)
|
||||
_try_head_kick_member(deps, &head_address, owner_signature, member)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn _try_head_kick_member(
|
||||
deps: DepsMut,
|
||||
owner: &Addr,
|
||||
member: IdentityKey,
|
||||
owner_signature: String,
|
||||
member: IdentityKeyRef<'_>,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
let head_bond = crate::mixnodes::helpers::must_get_mixnode_bond_by_owner(deps.storage, owner)?;
|
||||
Err(MixnetContractError::NotImplemented)
|
||||
// let existing_bond = crate::mixnodes::storage::mixnode_bonds()
|
||||
// .idx
|
||||
// .owner
|
||||
// .item(deps.storage, owner.clone())?
|
||||
// .ok_or(MixnetContractError::NoAssociatedMixNodeBond {
|
||||
// owner: owner.clone(),
|
||||
// })?
|
||||
// .1;
|
||||
|
||||
// make sure we're still in the mixnet
|
||||
ensure_bonded(&head_bond)?;
|
||||
// ensure_bonded(&existing_bond)?;
|
||||
|
||||
// make sure we're not trying to kick ourselves...
|
||||
if member == head_bond.identity() {
|
||||
return Err(MixnetContractError::CantLeaveOwnFamily {
|
||||
head: head_bond.identity().to_string(),
|
||||
member,
|
||||
});
|
||||
}
|
||||
// validate_node_identity_signature(
|
||||
// deps.as_ref(),
|
||||
// owner,
|
||||
// &owner_signature,
|
||||
// existing_bond.identity(),
|
||||
// )?;
|
||||
|
||||
// get the family details
|
||||
let family_head = FamilyHead::new(head_bond.identity());
|
||||
let family = get_family(&family_head, deps.storage)?;
|
||||
// let family_head = FamilyHead::new(existing_bond.identity());
|
||||
// let family = get_family(&family_head, deps.storage)?;
|
||||
// if !is_family_member(deps.storage, &family, member)? {
|
||||
// return Err(MixnetContractError::NotAMember {
|
||||
// head: family_head.identity().to_string(),
|
||||
// member: existing_bond.identity().to_string(),
|
||||
// });
|
||||
// }
|
||||
|
||||
// make sure the member we're trying to kick is an actual member
|
||||
if !is_family_member(deps.storage, &family, &member)? {
|
||||
return Err(MixnetContractError::NotAMember {
|
||||
head: family_head.identity().to_string(),
|
||||
member,
|
||||
});
|
||||
}
|
||||
|
||||
// finally get rid of the member
|
||||
remove_family_member(deps.storage, &member);
|
||||
Ok(Response::default())
|
||||
// remove_family_member(deps.storage, member);
|
||||
// Ok(Response::default())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -253,9 +322,9 @@ mod test {
|
||||
let cost_params = fixtures::mix_node_cost_params_fixture();
|
||||
|
||||
let (head_mixnode, head_bond_sig, head_keypair) = test.mixnode_with_signature(head, None);
|
||||
let (malicious_mixnode, malicious_bond_sig, _malicious_keypair) =
|
||||
let (malicious_mixnode, malicious_bond_sig, malicious_keypair) =
|
||||
test.mixnode_with_signature(malicious_head, None);
|
||||
let (member_mixnode, member_bond_sig, _member_keypair) =
|
||||
let (member_mixnode, member_bond_sig, member_keypair) =
|
||||
test.mixnode_with_signature(member, None);
|
||||
|
||||
crate::mixnodes::transactions::try_add_mixnode(
|
||||
@@ -288,14 +357,26 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
try_create_family(test.deps_mut(), mock_info(head, &[]), "test".to_string()).unwrap();
|
||||
let old_style_head_sig = head_keypair.private_key().sign_text(head);
|
||||
let old_style_malicious_head_sig =
|
||||
malicious_keypair.private_key().sign_text(malicious_head);
|
||||
let old_style_member_sig = member_keypair.private_key().sign_text(member);
|
||||
|
||||
try_create_family(
|
||||
test.deps_mut(),
|
||||
mock_info(head, &[]),
|
||||
old_style_head_sig,
|
||||
"test",
|
||||
)
|
||||
.unwrap();
|
||||
let family_head = FamilyHead::new(&head_mixnode.identity_key);
|
||||
assert!(get_family(&family_head, test.deps().storage).is_ok());
|
||||
|
||||
let nope = try_create_family(
|
||||
test.deps_mut(),
|
||||
mock_info(malicious_head, &[]),
|
||||
"test".to_string(),
|
||||
old_style_malicious_head_sig,
|
||||
"test",
|
||||
);
|
||||
|
||||
match nope {
|
||||
@@ -306,23 +387,24 @@ mod test {
|
||||
},
|
||||
}
|
||||
|
||||
let family = get_family_by_label("test".to_string(), test.deps().storage).unwrap();
|
||||
let family = get_family_by_label("test", test.deps().storage).unwrap();
|
||||
assert!(family.is_some());
|
||||
assert_eq!(family.unwrap().head_identity(), family_head.identity());
|
||||
|
||||
let family = get_family_by_head(family_head.identity(), test.deps().storage)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let family = get_family_by_head(family_head.identity(), test.deps().storage).unwrap();
|
||||
assert_eq!(family.head_identity(), family_head.identity());
|
||||
|
||||
let join_permit =
|
||||
test.generate_family_join_permit(&head_keypair, &member_mixnode.identity_key, false);
|
||||
let join_signature = head_keypair
|
||||
.private_key()
|
||||
.sign(member_mixnode.identity_key.as_bytes())
|
||||
.to_base58_string();
|
||||
|
||||
try_join_family(
|
||||
test.deps_mut(),
|
||||
mock_info(member, &[]),
|
||||
join_permit,
|
||||
family_head.clone(),
|
||||
Some(old_style_member_sig.clone()),
|
||||
join_signature.clone(),
|
||||
head_mixnode.identity_key.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -332,21 +414,25 @@ mod test {
|
||||
is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
|
||||
);
|
||||
|
||||
try_leave_family(test.deps_mut(), mock_info(member, &[]), family_head.clone()).unwrap();
|
||||
try_leave_family(
|
||||
test.deps_mut(),
|
||||
mock_info(member, &[]),
|
||||
old_style_member_sig.clone(),
|
||||
head_mixnode.identity_key.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let family = get_family(&family_head, test.deps().storage).unwrap();
|
||||
assert!(
|
||||
!is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
|
||||
);
|
||||
|
||||
let new_join_permit =
|
||||
test.generate_family_join_permit(&head_keypair, &member_mixnode.identity_key, false);
|
||||
|
||||
try_join_family(
|
||||
test.deps_mut(),
|
||||
mock_info(member, &[]),
|
||||
new_join_permit,
|
||||
family_head.clone(),
|
||||
Some(old_style_member_sig),
|
||||
join_signature,
|
||||
head_mixnode.identity_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -356,17 +442,16 @@ mod test {
|
||||
is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
|
||||
);
|
||||
|
||||
try_head_kick_member(
|
||||
test.deps_mut(),
|
||||
mock_info(head, &[]),
|
||||
member_mixnode.identity_key.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
// try_head_kick_member(
|
||||
// deps.as_mut(),
|
||||
// mock_info(&head, &[]),
|
||||
// head_sig.clone(),
|
||||
// &member_mixnode.identity_key.clone(),
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
let family = get_family(&family_head, test.deps().storage).unwrap();
|
||||
assert!(
|
||||
!is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
|
||||
);
|
||||
// let family = get_family(&family_head, test.deps().storage).unwrap();
|
||||
// assert!(!is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -383,13 +468,15 @@ mod test {
|
||||
|
||||
let head = "alice";
|
||||
|
||||
test.add_dummy_mixnode(head, None);
|
||||
let (_, keypair) = test.add_dummy_mixnode_with_proxy_and_keypair(head, None);
|
||||
let sig = keypair.private_key().sign_text(head);
|
||||
|
||||
let res = try_create_family_on_behalf(
|
||||
test.deps_mut(),
|
||||
mock_info(illegal_proxy.as_ref(), &[]),
|
||||
head.to_string(),
|
||||
"label".to_string(),
|
||||
sig,
|
||||
"label",
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
@@ -420,22 +507,23 @@ mod test {
|
||||
let new_member = "vin-diesel";
|
||||
|
||||
let (_, head_keys) = test.create_dummy_mixnode_with_new_family(head, label);
|
||||
let (_, member_keys) = test.add_dummy_mixnode_with_keypair(new_member, None);
|
||||
let (_, member_keys) = test.add_dummy_mixnode_with_proxy_and_keypair(new_member, None);
|
||||
|
||||
let join_permit = test.generate_family_join_permit(
|
||||
&head_keys,
|
||||
&member_keys.public_key().to_base58_string(),
|
||||
false,
|
||||
);
|
||||
// TODO: those signatures are WRONG and have to be c hanged
|
||||
let join_signature = head_keys
|
||||
.private_key()
|
||||
.sign_text(&member_keys.public_key().to_base58_string());
|
||||
|
||||
let member_sig = member_keys.private_key().sign_text(new_member);
|
||||
|
||||
let head_identity = head_keys.public_key().to_base58_string();
|
||||
let family_head = FamilyHead::new(&head_identity);
|
||||
let res = try_join_family_on_behalf(
|
||||
test.deps_mut(),
|
||||
mock_info(illegal_proxy.as_ref(), &[]),
|
||||
new_member.to_string(),
|
||||
join_permit,
|
||||
family_head,
|
||||
Some(member_sig),
|
||||
join_signature,
|
||||
head_identity,
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
@@ -466,30 +554,33 @@ mod test {
|
||||
let new_member = "vin-diesel";
|
||||
|
||||
let (_, head_keys) = test.create_dummy_mixnode_with_new_family(head, label);
|
||||
let (_, member_keys) = test.add_dummy_mixnode_with_keypair(new_member, None);
|
||||
let (_, member_keys) = test.add_dummy_mixnode_with_proxy_and_keypair(new_member, None);
|
||||
|
||||
let join_permit = test.generate_family_join_permit(
|
||||
&head_keys,
|
||||
&member_keys.public_key().to_base58_string(),
|
||||
true,
|
||||
);
|
||||
// TODO: those signatures are WRONG and have to be changed
|
||||
let join_signature = head_keys
|
||||
.private_key()
|
||||
.sign_text(&member_keys.public_key().to_base58_string());
|
||||
|
||||
let member_sig = member_keys.private_key().sign_text(new_member);
|
||||
|
||||
let head_identity = head_keys.public_key().to_base58_string();
|
||||
let family_head = FamilyHead::new(&head_identity);
|
||||
try_join_family_on_behalf(
|
||||
test.deps_mut(),
|
||||
mock_info(vesting_contract.as_ref(), &[]),
|
||||
new_member.to_string(),
|
||||
join_permit,
|
||||
family_head.clone(),
|
||||
Some(member_sig.clone()),
|
||||
join_signature,
|
||||
head_identity,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let leave_signature = member_sig;
|
||||
let res = try_leave_family_on_behalf(
|
||||
test.deps_mut(),
|
||||
mock_info(illegal_proxy.as_ref(), &[]),
|
||||
new_member.to_string(),
|
||||
family_head.clone(),
|
||||
leave_signature,
|
||||
head_keys.public_key().to_base58_string(),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
@@ -520,31 +611,33 @@ mod test {
|
||||
let new_member = "vin-diesel";
|
||||
|
||||
let (_, head_keys) = test.create_dummy_mixnode_with_new_family(head, label);
|
||||
let (_, member_keys) = test.add_dummy_mixnode_with_keypair(new_member, None);
|
||||
let (_, member_keys) = test.add_dummy_mixnode_with_proxy_and_keypair(new_member, None);
|
||||
|
||||
let join_permit = test.generate_family_join_permit(
|
||||
&head_keys,
|
||||
&member_keys.public_key().to_base58_string(),
|
||||
true,
|
||||
);
|
||||
// TODO: those signatures are WRONG and have to be c hanged
|
||||
let join_signature = head_keys
|
||||
.private_key()
|
||||
.sign_text(&member_keys.public_key().to_base58_string());
|
||||
|
||||
let member_sig = member_keys.private_key().sign_text(new_member);
|
||||
|
||||
let head_identity = head_keys.public_key().to_base58_string();
|
||||
let family_head = FamilyHead::new(&head_identity);
|
||||
|
||||
try_join_family_on_behalf(
|
||||
test.deps_mut(),
|
||||
mock_info(vesting_contract.as_ref(), &[]),
|
||||
new_member.to_string(),
|
||||
join_permit,
|
||||
family_head,
|
||||
Some(member_sig),
|
||||
join_signature,
|
||||
head_identity,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// TODO: a completely wrong signature is being used
|
||||
let res = try_head_kick_member_on_behalf(
|
||||
test.deps_mut(),
|
||||
mock_info(illegal_proxy.as_ref(), &[]),
|
||||
head.to_string(),
|
||||
member_keys.public_key().to_base58_string(),
|
||||
head_keys.private_key().sign_text(head),
|
||||
&member_keys.public_key().to_base58_string(),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
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};
|
||||
@@ -18,7 +17,10 @@ pub(crate) fn verify_gateway_bonding_signature(
|
||||
signature: MessageSignature,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
// recover the public key
|
||||
let public_key = decode_ed25519_identity_key(&gateway.identity_key)?;
|
||||
let mut public_key = [0u8; 32];
|
||||
bs58::decode(&gateway.identity_key)
|
||||
.into(&mut public_key)
|
||||
.map_err(|err| MixnetContractError::MalformedEd25519IdentityKey(err.to_string()))?;
|
||||
|
||||
// reconstruct the payload
|
||||
let nonce = signing_storage::get_signing_nonce(deps.storage, sender.clone())?;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
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};
|
||||
@@ -19,7 +18,10 @@ pub(crate) fn verify_mixnode_bonding_signature(
|
||||
signature: MessageSignature,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
// recover the public key
|
||||
let public_key = decode_ed25519_identity_key(&mixnode.identity_key)?;
|
||||
let mut public_key = [0u8; 32];
|
||||
bs58::decode(&mixnode.identity_key)
|
||||
.into(&mut public_key)
|
||||
.map_err(|err| MixnetContractError::MalformedEd25519IdentityKey(err.to_string()))?;
|
||||
|
||||
// reconstruct the payload
|
||||
let nonce = signing_storage::get_signing_nonce(deps.storage, sender.clone())?;
|
||||
|
||||
@@ -245,7 +245,12 @@ pub(crate) fn _try_remove_mixnode(
|
||||
owner: Addr,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
let existing_bond = must_get_mixnode_bond_by_owner(deps.storage, &owner)?;
|
||||
let existing_bond = storage::mixnode_bonds()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.storage, owner.clone())?
|
||||
.ok_or(MixnetContractError::NoAssociatedMixNodeBond { owner })?
|
||||
.1;
|
||||
|
||||
// unbonding is only allowed if the epoch is currently not in the process of being advanced
|
||||
ensure_epoch_in_progress_state(deps.storage)?;
|
||||
|
||||
@@ -1,2 +1,18 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::interval::storage as interval_storage;
|
||||
use cosmwasm_std::Storage;
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::EpochStatus;
|
||||
|
||||
pub(crate) fn create_epoch_status(storage: &mut dyn Storage) -> Result<(), MixnetContractError> {
|
||||
let current_rewarding_validator =
|
||||
crate::mixnet_contract_settings::storage::rewarding_validator_address(storage)?;
|
||||
interval_storage::save_current_epoch_status(
|
||||
storage,
|
||||
&EpochStatus::new(current_rewarding_validator),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
use crate::gateways::storage as gateways_storage;
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use cosmwasm_std::{wasm_execute, Addr, BankMsg, Coin, CosmosMsg, MessageInfo, Response, Storage};
|
||||
use cosmwasm_std::{
|
||||
wasm_execute, Addr, BankMsg, Coin, CosmosMsg, Deps, MessageInfo, Response, Storage,
|
||||
};
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
use mixnet_contract_common::{EpochState, EpochStatus, IdentityKeyRef, MixId, MixNodeBond};
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
@@ -369,19 +371,184 @@ pub(crate) fn ensure_no_existing_bond(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn decode_ed25519_identity_key(
|
||||
encoded: IdentityKeyRef,
|
||||
) -> Result<[u8; 32], MixnetContractError> {
|
||||
let mut public_key = [0u8; 32];
|
||||
let used = bs58::decode(encoded)
|
||||
.into(&mut public_key)
|
||||
.map_err(|err| MixnetContractError::MalformedEd25519IdentityKey(err.to_string()))?;
|
||||
pub fn validate_node_identity_signature(
|
||||
deps: Deps<'_>,
|
||||
owner: &Addr,
|
||||
signature: &str,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
validate_ed25519_signature(deps, owner.as_bytes(), signature, identity)
|
||||
}
|
||||
|
||||
if used != 32 {
|
||||
pub fn validate_family_signature(
|
||||
deps: Deps<'_>,
|
||||
family_member: IdentityKeyRef<'_>,
|
||||
signature: &str,
|
||||
family_head: IdentityKeyRef<'_>,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
validate_ed25519_signature(deps, family_member.as_bytes(), signature, family_head)
|
||||
}
|
||||
|
||||
pub(crate) fn validate_ed25519_signature(
|
||||
deps: Deps<'_>,
|
||||
signed_bytes: &[u8],
|
||||
signature: &str,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
let mut identity_bytes = [0u8; 32];
|
||||
let mut signature_bytes = [0u8; 64];
|
||||
|
||||
let identity_used_bytes = bs58::decode(identity)
|
||||
.into(&mut identity_bytes)
|
||||
.map_err(|err| MixnetContractError::MalformedEd25519IdentityKey(err.to_string()))?;
|
||||
let signature_used_bytes = bs58::decode(signature)
|
||||
.into(&mut signature_bytes)
|
||||
.map_err(|err| MixnetContractError::MalformedEd25519Signature(err.to_string()))?;
|
||||
|
||||
if identity_used_bytes != 32 {
|
||||
return Err(MixnetContractError::MalformedEd25519IdentityKey(
|
||||
"Too few bytes provided for the public key".into(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(public_key)
|
||||
if signature_used_bytes != 64 {
|
||||
return Err(MixnetContractError::MalformedEd25519Signature(
|
||||
"Too few bytes provided for the signature".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let res = deps
|
||||
.api
|
||||
.ed25519_verify(signed_bytes, &signature_bytes, &identity_bytes)
|
||||
.map_err(cosmwasm_std::StdError::verification_err)?;
|
||||
if !res {
|
||||
Err(MixnetContractError::InvalidEd25519Signature)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use cosmwasm_std::testing::mock_dependencies;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
|
||||
#[test]
|
||||
fn validating_node_signature() {
|
||||
let deps = mock_dependencies();
|
||||
|
||||
// since those tests are NOT compiled to wasm, we can use rng-related dependency
|
||||
let dummy_seed = [1u8; 32];
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||
|
||||
let short_bs58 = "2SfEgZ4aQUr3HSwqE";
|
||||
let long_bs58 = "g34PyULki9fc3FqKobj5wdVNCaWAt1M9oZowyyMFfWSCejxg7wt574piZVjqjFEN2UXsgZ56KTkKf3jnWD4DJ2Gsf7KXQAvptFfcYRrZHTjMVo3NXcBSNm3wDBKZWZURzp4Fixv";
|
||||
|
||||
let address1 = Addr::unchecked("some-dummy-address1");
|
||||
let address2 = Addr::unchecked("some-dummy-address2");
|
||||
|
||||
let keypair1 = identity::KeyPair::new(&mut rng);
|
||||
let keypair2 = identity::KeyPair::new(&mut rng);
|
||||
|
||||
let sig_addr1_key1 = keypair1
|
||||
.private_key()
|
||||
.sign(address1.as_bytes())
|
||||
.to_base58_string();
|
||||
let sig_addr2_key1 = keypair1
|
||||
.private_key()
|
||||
.sign(address2.as_bytes())
|
||||
.to_base58_string();
|
||||
let sig_addr1_key2 = keypair2
|
||||
.private_key()
|
||||
.sign(address1.as_bytes())
|
||||
.to_base58_string();
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::MalformedEd25519IdentityKey(
|
||||
"buffer provided to decode base58 encoded string into was too small".into()
|
||||
)),
|
||||
validate_node_identity_signature(deps.as_ref(), &address1, &sig_addr1_key1, long_bs58,)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::MalformedEd25519Signature(
|
||||
"buffer provided to decode base58 encoded string into was too small".into()
|
||||
)),
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address1,
|
||||
long_bs58.into(),
|
||||
&keypair1.public_key().to_base58_string(),
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::MalformedEd25519IdentityKey(
|
||||
"Too few bytes provided for the public key".into()
|
||||
)),
|
||||
validate_node_identity_signature(deps.as_ref(), &address1, &sig_addr1_key1, short_bs58,)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::MalformedEd25519Signature(
|
||||
"Too few bytes provided for the signature".into()
|
||||
)),
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address1,
|
||||
short_bs58.into(),
|
||||
&keypair1.public_key().to_base58_string(),
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::InvalidEd25519Signature),
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address1,
|
||||
&sig_addr1_key1,
|
||||
&keypair2.public_key().to_base58_string(),
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::InvalidEd25519Signature),
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address1,
|
||||
&sig_addr2_key1,
|
||||
&keypair1.public_key().to_base58_string(),
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::InvalidEd25519Signature),
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address2,
|
||||
&sig_addr1_key1,
|
||||
&keypair1.public_key().to_base58_string(),
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Err(MixnetContractError::InvalidEd25519Signature),
|
||||
validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address1,
|
||||
&sig_addr1_key2,
|
||||
&keypair1.public_key().to_base58_string(),
|
||||
)
|
||||
);
|
||||
|
||||
assert!(validate_node_identity_signature(
|
||||
deps.as_ref(),
|
||||
&address1,
|
||||
&sig_addr1_key1,
|
||||
&keypair1.public_key().to_base58_string(),
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ pub mod test_helpers {
|
||||
use mixnet_contract_common::events::{
|
||||
may_find_attribute, MixnetEventType, DELEGATES_REWARD_KEY, OPERATOR_REWARD_KEY,
|
||||
};
|
||||
use mixnet_contract_common::families::FamilyHead;
|
||||
use mixnet_contract_common::mixnode::{MixNodeRewarding, UnbondedMixnode};
|
||||
use mixnet_contract_common::pending_events::{PendingEpochEventData, PendingIntervalEventData};
|
||||
use mixnet_contract_common::reward_params::{Performance, RewardingParams};
|
||||
@@ -62,10 +61,10 @@ pub mod test_helpers {
|
||||
use mixnet_contract_common::rewarding::simulator::Simulator;
|
||||
use mixnet_contract_common::rewarding::RewardDistribution;
|
||||
use mixnet_contract_common::{
|
||||
construct_family_join_permit, Delegation, EpochState, EpochStatus, Gateway,
|
||||
GatewayBondingPayload, IdentityKey, IdentityKeyRef, InitialRewardingParams, InstantiateMsg,
|
||||
Interval, MixId, MixNode, MixNodeBond, MixnodeBondingPayload, Percent,
|
||||
RewardedSetNodeStatus, SignableGatewayBondingMsg, SignableMixNodeBondingMsg,
|
||||
Delegation, EpochState, EpochStatus, Gateway, GatewayBondingPayload, IdentityKey,
|
||||
InitialRewardingParams, InstantiateMsg, Interval, MixId, MixNode, MixNodeBond,
|
||||
MixnodeBondingPayload, Percent, RewardedSetNodeStatus, SignableGatewayBondingMsg,
|
||||
SignableMixNodeBondingMsg,
|
||||
};
|
||||
use nym_contracts_common::signing::{
|
||||
ContractMessageContent, MessageSignature, SignableMessage, SigningAlgorithm, SigningPurpose,
|
||||
@@ -170,64 +169,26 @@ pub mod test_helpers {
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn generate_family_join_permit(
|
||||
&mut self,
|
||||
family_owner_keys: &identity::KeyPair,
|
||||
member_node: IdentityKeyRef,
|
||||
vesting: bool,
|
||||
) -> MessageSignature {
|
||||
let identity = family_owner_keys.public_key().to_base58_string();
|
||||
|
||||
let head_mixnode = mixnodes_storage::mixnode_bonds()
|
||||
.idx
|
||||
.identity_key
|
||||
.item(self.deps().storage, identity.clone())
|
||||
.unwrap()
|
||||
.map(|record| record.1)
|
||||
.unwrap();
|
||||
|
||||
let family_head = FamilyHead::new(&identity);
|
||||
let owner = head_mixnode.owner;
|
||||
|
||||
let nonce =
|
||||
signing_storage::get_signing_nonce(self.deps().storage, owner.clone()).unwrap();
|
||||
|
||||
let proxy = if vesting {
|
||||
Some(self.vesting_contract())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let msg =
|
||||
construct_family_join_permit(nonce, family_head, proxy, member_node.to_owned());
|
||||
|
||||
let sig_bytes = family_owner_keys
|
||||
.private_key()
|
||||
.sign(&msg.to_plaintext().unwrap())
|
||||
.to_bytes();
|
||||
MessageSignature::from(sig_bytes.as_ref())
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn join_family(
|
||||
&mut self,
|
||||
member: &str,
|
||||
member_keys: &identity::KeyPair,
|
||||
head_keys: &identity::KeyPair,
|
||||
vesting: bool,
|
||||
) {
|
||||
let member_identity = member_keys.public_key().to_base58_string();
|
||||
let identity_signature = member_keys.private_key().sign_text(member);
|
||||
let join_signature = head_keys
|
||||
.private_key()
|
||||
.sign(&member_keys.public_key().to_bytes())
|
||||
.to_base58_string();
|
||||
let head_identity = head_keys.public_key().to_base58_string();
|
||||
|
||||
let join_permit =
|
||||
self.generate_family_join_permit(head_keys, &member_identity, vesting);
|
||||
let family_head = FamilyHead::new(&head_identity);
|
||||
|
||||
try_join_family(
|
||||
self.deps_mut(),
|
||||
mock_info(member, &[]),
|
||||
join_permit,
|
||||
family_head,
|
||||
Some(identity_signature),
|
||||
join_signature,
|
||||
head_identity,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -238,8 +199,9 @@ pub mod test_helpers {
|
||||
label: &str,
|
||||
) -> (MixId, identity::KeyPair) {
|
||||
let (mix_id, keys) = self.add_dummy_mixnode_with_proxy_and_keypair(head, None);
|
||||
let sig = keys.private_key().sign_text(head);
|
||||
|
||||
try_create_family(self.deps_mut(), mock_info(head, &[]), label.to_string()).unwrap();
|
||||
try_create_family(self.deps_mut(), mock_info(head, &[]), sig, label).unwrap();
|
||||
(mix_id, keys)
|
||||
}
|
||||
|
||||
@@ -328,53 +290,6 @@ pub mod test_helpers {
|
||||
ed25519_sign_message(msg, key)
|
||||
}
|
||||
|
||||
pub fn add_dummy_mixnode_with_keypair(
|
||||
&mut self,
|
||||
owner: &str,
|
||||
stake: Option<Uint128>,
|
||||
) -> (MixId, identity::KeyPair) {
|
||||
let stake = self.make_mix_pledge(stake);
|
||||
|
||||
let keypair = identity::KeyPair::new(&mut self.rng);
|
||||
let identity_key = keypair.public_key().to_base58_string();
|
||||
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
|
||||
|
||||
let mixnode = MixNode {
|
||||
identity_key,
|
||||
sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
|
||||
..tests::fixtures::mix_node_fixture()
|
||||
};
|
||||
|
||||
let msg = mixnode_bonding_sign_payload(
|
||||
self.deps(),
|
||||
owner,
|
||||
None,
|
||||
mixnode.clone(),
|
||||
stake.clone(),
|
||||
);
|
||||
let owner_signature = ed25519_sign_message(msg, keypair.private_key());
|
||||
|
||||
let info = mock_info(owner, &stake);
|
||||
let current_id_counter = mixnodes_storage::MIXNODE_ID_COUNTER
|
||||
.may_load(self.deps().storage)
|
||||
.unwrap()
|
||||
.unwrap_or_default();
|
||||
|
||||
let env = self.env();
|
||||
try_add_mixnode(
|
||||
self.deps_mut(),
|
||||
env,
|
||||
info,
|
||||
mixnode,
|
||||
tests::fixtures::mix_node_cost_params_fixture(),
|
||||
owner_signature,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// newly added mixnode gets assigned the current counter + 1
|
||||
(current_id_counter + 1, keypair)
|
||||
}
|
||||
|
||||
pub fn add_dummy_mixnode_with_proxy_and_keypair(
|
||||
&mut self,
|
||||
owner: &str,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-vesting-contract"
|
||||
version = "1.3.0"
|
||||
version = "1.2.0"
|
||||
description = "Nym vesting contract"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -20,9 +20,9 @@ name = "vesting_contract"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.4.0" }
|
||||
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.4.0" }
|
||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.3.0" }
|
||||
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", package = "nym-contracts-common", version = "0.3.0" }
|
||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.3.0" }
|
||||
|
||||
cosmwasm-std = { workspace = true }
|
||||
cosmwasm-derive = { workspace = true }
|
||||
|
||||
@@ -11,10 +11,9 @@ use contracts_common::signing::MessageSignature;
|
||||
use contracts_common::ContractBuildInformation;
|
||||
use cosmwasm_std::{
|
||||
coin, entry_point, to_binary, Addr, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Order,
|
||||
QueryResponse, Response, StdResult, Timestamp, Uint128,
|
||||
QueryResponse, Response, StdError, StdResult, Timestamp, Uint128,
|
||||
};
|
||||
use cw_storage_plus::Bound;
|
||||
use mixnet_contract_common::families::FamilyHead;
|
||||
use mixnet_contract_common::gateway::GatewayConfigUpdate;
|
||||
use mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
|
||||
use mixnet_contract_common::{Gateway, MixId, MixNode};
|
||||
@@ -76,6 +75,15 @@ pub fn instantiate(
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
// this is the first migration that uses cw2 standard and thus the value in the storage doesn't yet exist
|
||||
// set it instead.
|
||||
if matches!(
|
||||
cw2::get_contract_version(deps.storage),
|
||||
Err(StdError::NotFound { .. })
|
||||
) {
|
||||
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
}
|
||||
|
||||
// note: don't remove this particular bit of code as we have to ALWAYS check whether we have to update the stored version
|
||||
let version: Version =
|
||||
CONTRACT_VERSION
|
||||
@@ -98,7 +106,7 @@ pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respons
|
||||
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
|
||||
// If state structure changed in any contract version in the way migration is needed, it
|
||||
// should occur here, for example anything from `crate::queued_migrations::`
|
||||
// should occur here
|
||||
}
|
||||
|
||||
Ok(Response::new())
|
||||
@@ -112,13 +120,28 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::CreateFamily { label } => try_create_family(info, deps, label),
|
||||
ExecuteMsg::CreateFamily {
|
||||
owner_signature,
|
||||
label,
|
||||
} => try_create_family(info, deps, owner_signature, label),
|
||||
ExecuteMsg::JoinFamily {
|
||||
join_permit,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head,
|
||||
} => try_join_family(info, deps, join_permit, family_head),
|
||||
ExecuteMsg::LeaveFamily { family_head } => try_leave_family(info, deps, family_head),
|
||||
ExecuteMsg::KickFamilyMember { member } => try_kick_family_member(info, deps, member),
|
||||
} => try_join_family(
|
||||
info,
|
||||
deps,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head,
|
||||
),
|
||||
ExecuteMsg::LeaveFamily {
|
||||
node_identity_signature,
|
||||
family_head,
|
||||
} => try_leave_family(info, deps, node_identity_signature, family_head),
|
||||
ExecuteMsg::KickFamilyMember { signature, member } => {
|
||||
try_kick_family_member(info, deps, signature, member)
|
||||
}
|
||||
ExecuteMsg::UpdateLockedPledgeCap { address, cap } => {
|
||||
try_update_locked_pledge_cap(address, cap, info, deps)
|
||||
}
|
||||
@@ -212,35 +235,44 @@ pub fn execute(
|
||||
pub fn try_create_family(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_ref(), deps.storage, deps.api)?;
|
||||
account.try_create_family(deps.storage, label)
|
||||
account.try_create_family(deps.storage, owner_signature, label)
|
||||
}
|
||||
pub fn try_join_family(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_signature: String,
|
||||
family_head: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_ref(), deps.storage, deps.api)?;
|
||||
account.try_join_family(deps.storage, join_permit, family_head)
|
||||
account.try_join_family(
|
||||
deps.storage,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
&family_head,
|
||||
)
|
||||
}
|
||||
pub fn try_leave_family(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_head: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_ref(), deps.storage, deps.api)?;
|
||||
account.try_leave_family(deps.storage, family_head)
|
||||
account.try_leave_family(deps.storage, node_identity_signature, &family_head)
|
||||
}
|
||||
pub fn try_kick_family_member(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
signature: String,
|
||||
member: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_ref(), deps.storage, deps.api)?;
|
||||
account.try_head_kick_member(deps.storage, &member)
|
||||
account.try_head_kick_member(deps.storage, signature, &member)
|
||||
}
|
||||
|
||||
/// Update locked_pledge_cap, the hard cap for staking/bonding with unvested tokens.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
use crate::errors::ContractError;
|
||||
use contracts_common::signing::MessageSignature;
|
||||
use cosmwasm_std::{Response, Storage};
|
||||
use mixnet_contract_common::families::FamilyHead;
|
||||
use mixnet_contract_common::IdentityKeyRef;
|
||||
|
||||
pub trait NodeFamilies {
|
||||
fn try_create_family(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
) -> Result<Response, ContractError>;
|
||||
|
||||
fn try_join_family(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_signature: String,
|
||||
family_head: IdentityKeyRef,
|
||||
) -> Result<Response, ContractError>;
|
||||
|
||||
fn try_leave_family(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
family_head: FamilyHead,
|
||||
signature: String,
|
||||
family_head: IdentityKeyRef,
|
||||
) -> Result<Response, ContractError>;
|
||||
|
||||
fn try_head_kick_member(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
signature: String,
|
||||
member: IdentityKeyRef<'_>,
|
||||
) -> Result<Response, ContractError>;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use super::Account;
|
||||
use crate::{errors::ContractError, storage::MIXNET_CONTRACT_ADDRESS, traits::NodeFamilies};
|
||||
use contracts_common::signing::MessageSignature;
|
||||
use cosmwasm_std::{wasm_execute, Response, Storage};
|
||||
use mixnet_contract_common::families::FamilyHead;
|
||||
use mixnet_contract_common::{ExecuteMsg as MixnetExecuteMsg, IdentityKeyRef};
|
||||
|
||||
impl NodeFamilies for Account {
|
||||
fn try_create_family(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
owner_signature: String,
|
||||
label: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::CreateFamilyOnBehalf {
|
||||
owner_address: self.owner_address().into_string(),
|
||||
owner_address: self.owner_address().to_string(),
|
||||
owner_signature,
|
||||
label,
|
||||
};
|
||||
|
||||
@@ -24,13 +24,15 @@ impl NodeFamilies for Account {
|
||||
fn try_join_family(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
join_permit: MessageSignature,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_signature: String,
|
||||
family_head: IdentityKeyRef,
|
||||
) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::JoinFamilyOnBehalf {
|
||||
member_address: self.owner_address().to_string(),
|
||||
join_permit,
|
||||
family_head,
|
||||
node_identity_signature,
|
||||
family_signature,
|
||||
family_head: family_head.to_string(),
|
||||
};
|
||||
|
||||
let msg = wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![])?;
|
||||
@@ -41,11 +43,13 @@ impl NodeFamilies for Account {
|
||||
fn try_leave_family(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
family_head: FamilyHead,
|
||||
node_identity_signature: String,
|
||||
family_head: IdentityKeyRef,
|
||||
) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::LeaveFamilyOnBehalf {
|
||||
member_address: self.owner_address().to_string(),
|
||||
family_head,
|
||||
node_identity_signature,
|
||||
family_head: family_head.to_string(),
|
||||
};
|
||||
|
||||
let msg = wasm_execute(MIXNET_CONTRACT_ADDRESS.load(storage)?, &msg, vec![])?;
|
||||
@@ -56,10 +60,12 @@ impl NodeFamilies for Account {
|
||||
fn try_head_kick_member(
|
||||
&self,
|
||||
storage: &dyn Storage,
|
||||
signature: String,
|
||||
member: IdentityKeyRef<'_>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::KickFamilyMemberOnBehalf {
|
||||
head_address: self.owner_address().to_string(),
|
||||
signature,
|
||||
member: member.to_string(),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.14"
|
||||
version = "1.1.13"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -189,9 +189,9 @@ impl<St: Storage> ConnectionHandler<St> {
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("ConnectionHandler: received shutdown");
|
||||
}
|
||||
framed_sphinx_packet = framed_conn.next() => {
|
||||
Some(framed_sphinx_packet) = framed_conn.next() => {
|
||||
match framed_sphinx_packet {
|
||||
Some(Ok(framed_sphinx_packet)) => {
|
||||
Ok(framed_sphinx_packet) => {
|
||||
// TODO: benchmark spawning tokio task with full processing vs just processing it
|
||||
// synchronously under higher load in single and multi-threaded situation.
|
||||
|
||||
@@ -200,13 +200,12 @@ impl<St: Storage> ConnectionHandler<St> {
|
||||
// that change would only slow things down
|
||||
self.handle_received_packet(framed_sphinx_packet).await;
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
Err(err) => {
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {err}. Closing the socket",
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => break, // stream got closed by remote
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.15"
|
||||
version = "1.1.14"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -85,9 +85,9 @@ impl ConnectionHandler {
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("ConnectionHandler: received shutdown");
|
||||
}
|
||||
framed_sphinx_packet = framed_conn.next() => {
|
||||
Some(framed_sphinx_packet) = framed_conn.next() => {
|
||||
match framed_sphinx_packet {
|
||||
Some(Ok(framed_sphinx_packet)) => {
|
||||
Ok(framed_sphinx_packet) => {
|
||||
// TODO: benchmark spawning tokio task with full processing vs just processing it
|
||||
// synchronously (without delaying inside of course,
|
||||
// delay is moved to a global DelayQueue)
|
||||
@@ -98,13 +98,12 @@ impl ConnectionHandler {
|
||||
// that change would only slow things down
|
||||
self.handle_received_packet(framed_sphinx_packet);
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
Err(err) => {
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {err}. Closing the socket",
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => break, // stream got closed by remote
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-api"
|
||||
version = "1.1.15"
|
||||
version = "1.1.14"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::node_status_api::models::NymApiStorageError;
|
||||
use nym_mixnet_contract_common::{EpochState, MixId};
|
||||
use nym_mixnet_contract_common::EpochState;
|
||||
use thiserror::Error;
|
||||
use validator_client::nyxd::error::NyxdError;
|
||||
use validator_client::nyxd::AccountId;
|
||||
@@ -22,9 +22,6 @@ pub enum RewardingError {
|
||||
operation: String,
|
||||
},
|
||||
|
||||
#[error("it seems the current epoch is in mid-rewarding state (last rewarded is {last_rewarded}). With our current nym-api this shouldn't have been possible. Manual intervention is required.")]
|
||||
MidMixRewarding { last_rewarded: MixId },
|
||||
|
||||
// #[error("There were no mixnodes to reward (network is dead)")]
|
||||
// NoMixnodesToReward,
|
||||
#[error("Failed to execute the smart contract - {0}")]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::epoch_operations::error::RewardingError;
|
||||
use crate::support::storage::models::RewardingReport;
|
||||
use crate::RewardedSetUpdater;
|
||||
use nym_mixnet_contract_common::reward_params::Performance;
|
||||
use nym_mixnet_contract_common::{EpochState, ExecuteMsg, Interval, MixId};
|
||||
@@ -41,15 +42,8 @@ impl RewardedSetUpdater {
|
||||
warn!("we seem to have crashed mid epoch operations... no need to reward mixnodes as we've already done that! (or this could be a false positive if there were no nodes to reward - to fix this warning later)");
|
||||
Ok(())
|
||||
}
|
||||
EpochState::Rewarding { last_rewarded, .. } => {
|
||||
EpochState::Rewarding { .. } => {
|
||||
log::info!("Rewarding the current rewarded set...");
|
||||
|
||||
// with how the nym-api is currently coded, this should never happen as we're always
|
||||
// rewarding ALL mixnodes at once, but who knows what we might decide to do in the future...
|
||||
if last_rewarded != 0 {
|
||||
return Err(RewardingError::MidMixRewarding { last_rewarded });
|
||||
}
|
||||
|
||||
if let Err(err) = self._reward_current_rewarded_set(current_interval).await {
|
||||
log::error!("FAILED to reward rewarded set - {err}");
|
||||
Err(err)
|
||||
@@ -68,8 +62,17 @@ impl RewardedSetUpdater {
|
||||
let mut to_reward = self.nodes_to_reward(current_interval).await;
|
||||
to_reward.sort_by_key(|a| a.mix_id);
|
||||
|
||||
if let Some(existing_report) = self
|
||||
.storage
|
||||
.get_rewarding_report(current_interval.current_epoch_absolute_id())
|
||||
.await?
|
||||
{
|
||||
warn!("We have already rewarded mixnodes for this rewarding epoch ({}). {} nodes should have gotten rewards", existing_report.absolute_epoch_id, existing_report.eligible_mixnodes);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if to_reward.is_empty() {
|
||||
error!("There are no nodes to reward in this epoch - we shouldn't have been in the 'Rewarding' state!");
|
||||
info!("There are no nodes to reward in this epoch");
|
||||
} else if let Err(err) = self.nyxd_client.send_rewarding_messages(&to_reward).await {
|
||||
error!(
|
||||
"failed to perform mixnode rewarding for epoch {}! Error encountered: {err}",
|
||||
@@ -80,6 +83,15 @@ impl RewardedSetUpdater {
|
||||
|
||||
log::info!("rewarded {} mixnodes...", to_reward.len());
|
||||
|
||||
let rewarding_report = RewardingReport {
|
||||
absolute_epoch_id: current_interval.current_epoch_absolute_id(),
|
||||
eligible_mixnodes: to_reward.len() as u32,
|
||||
};
|
||||
|
||||
self.storage
|
||||
.insert_rewarding_report(rewarding_report)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -867,7 +867,6 @@ impl StorageManager {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `report`: report to insert into the database
|
||||
#[allow(unused)]
|
||||
pub(crate) async fn insert_rewarding_report(
|
||||
&self,
|
||||
report: RewardingReport,
|
||||
@@ -886,7 +885,6 @@ impl StorageManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) async fn get_rewarding_report(
|
||||
&self,
|
||||
absolute_epoch_id: EpochId,
|
||||
|
||||
@@ -9,8 +9,8 @@ use crate::node_status_api::models::{
|
||||
};
|
||||
use crate::node_status_api::{ONE_DAY, ONE_HOUR};
|
||||
use crate::storage::manager::StorageManager;
|
||||
use crate::storage::models::{NodeStatus, TestingRoute};
|
||||
use nym_mixnet_contract_common::MixId;
|
||||
use crate::storage::models::{NodeStatus, RewardingReport, TestingRoute};
|
||||
use nym_mixnet_contract_common::{EpochId, MixId};
|
||||
use rocket::fairing::AdHoc;
|
||||
use sqlx::ConnectOptions;
|
||||
use std::path::PathBuf;
|
||||
@@ -717,6 +717,26 @@ impl NymApiStorage {
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
pub(crate) async fn insert_rewarding_report(
|
||||
&self,
|
||||
report: RewardingReport,
|
||||
) -> Result<(), NymApiStorageError> {
|
||||
self.manager
|
||||
.insert_rewarding_report(report)
|
||||
.await
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_rewarding_report(
|
||||
&self,
|
||||
absolute_epoch_id: EpochId,
|
||||
) -> Result<Option<RewardingReport>, NymApiStorageError> {
|
||||
self.manager
|
||||
.get_rewarding_report(absolute_epoch_id)
|
||||
.await
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_blinded_signature_response(
|
||||
&self,
|
||||
tx_hash: &str,
|
||||
|
||||
@@ -41,8 +41,6 @@ pub(crate) struct TestingRoute {
|
||||
pub(crate) monitor_run_db_id: i64,
|
||||
}
|
||||
|
||||
// for now let's leave it here to have a data model to use with existing database tables
|
||||
#[allow(unused)]
|
||||
pub(crate) struct RewardingReport {
|
||||
// references particular interval_rewarding
|
||||
pub(crate) absolute_epoch_id: u32,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nym/nym-connect",
|
||||
"version": "1.1.13",
|
||||
"version": "1.1.12",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-connect"
|
||||
version = "1.1.13"
|
||||
version = "1.1.12"
|
||||
description = "nym-connect"
|
||||
authors = ["Nym Technologies SA"]
|
||||
license = ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "nym-connect",
|
||||
"version": "1.1.13"
|
||||
"version": "1.1.12"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
||||
@@ -115,7 +115,6 @@
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.5.0",
|
||||
"webpack-favicons": "^1.3.8",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"yaml-loader": "^0.8.0"
|
||||
}
|
||||
|
||||
@@ -6,10 +6,19 @@ const entry = {
|
||||
app: path.resolve(__dirname, 'src/index.tsx'),
|
||||
};
|
||||
|
||||
module.exports = merge(common, {
|
||||
const config = merge(common, {
|
||||
mode: 'production',
|
||||
node: {
|
||||
__dirname: false,
|
||||
},
|
||||
entry,
|
||||
});
|
||||
|
||||
// Remove WebpackFavicons plugin as it makes FDroid build more
|
||||
// difficult to configure since webpack-favicons depends on sharp,
|
||||
// which depends on system library libvips
|
||||
// As we are building for mobile, this is useless anyway
|
||||
// TODO do not base deletion on index
|
||||
config.plugins.splice(2, 1);
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -2,18 +2,6 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.2.0] (2023-04-04)
|
||||
|
||||
- Add Version and Location to gateway settings ([#3266])
|
||||
- Wallet - bonding screen - short info with link ([#3179])
|
||||
- Wallet - discrepancies figma vs wallet ([#2183])
|
||||
- Wallet - If a gateway is bonded show gateway settings in the node settings: ([#2242])
|
||||
|
||||
[#3266]: https://github.com/nymtech/nym/issues/3266
|
||||
[#3179]: https://github.com/nymtech/nym/issues/3179
|
||||
[#2183]: https://github.com/nymtech/nym/issues/2183
|
||||
[#2242]: https://github.com/nymtech/nym/issues/2242
|
||||
|
||||
## [v1.1.12] (2023-03-15)
|
||||
|
||||
- Wallet - in the vesting section separate the "Unlocked transferable tokens" into "Unlocked vesting tokens" and "Transferable rewards" for better clarity ([#3132])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nymproject/nym-wallet-app",
|
||||
"version": "1.1.13",
|
||||
"version": "1.1.12",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym_wallet"
|
||||
version = "1.1.13"
|
||||
version = "1.1.12"
|
||||
description = "Nym Native Wallet"
|
||||
authors = ["Nym Technologies SA"]
|
||||
license = ""
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user