Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6dbb3fbd3f | |||
| 95b6ac50be | |||
| 5f2247ab83 | |||
| 842bcfa782 | |||
| c2938e0672 | |||
| 278516ad11 | |||
| ce241339bf | |||
| 8d7428923a | |||
| 4a1a4b6415 |
Generated
+24
-44
@@ -549,7 +549,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "client-core"
|
name = "client-core"
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"crypto",
|
"crypto",
|
||||||
@@ -750,31 +750,31 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-crypto"
|
name = "cosmwasm-crypto"
|
||||||
version = "1.0.0-beta6"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dddc1443004c6340e55ca66d98e9d2f1a44aadf4ce2bed2c4f29baa8a15e7b7"
|
checksum = "88c2565b1e73a816fb659ef4838fc356143fbd35f43c48a51d2d7d4e5d6679d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"ed25519-zebra",
|
"ed25519-zebra",
|
||||||
"k256 0.9.6",
|
"k256 0.9.6",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.6.3",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-derive"
|
name = "cosmwasm-derive"
|
||||||
version = "1.0.0-beta6"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe4f0f10f165b8bcc558a13cddb498140960544519aa0581532c766dd80b5598"
|
checksum = "fa89fcdf8dbbe0088e663d0a814aa7368e7ebe8fb045a3a150fb5fdc2ffe3b45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-std"
|
name = "cosmwasm-std"
|
||||||
version = "1.0.0-beta6"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f0f3145097b692b2d95fa5d2c7c6fdd60f193ccc709857e7e1987a608725300"
|
checksum = "bcb8f99a61d0b9069e1afc80a4ffea87dcc3523edd992080923870b13a677da0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"cosmwasm-crypto",
|
"cosmwasm-crypto",
|
||||||
@@ -1071,20 +1071,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cw-storage-plus"
|
name = "cw-storage-plus"
|
||||||
version = "0.11.1"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261"
|
checksum = "5e8b7f9a758c030d375520df947323c052704f784561fc28dcaab4f988c50a30"
|
||||||
dependencies = [
|
|
||||||
"cosmwasm-std",
|
|
||||||
"schemars",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cw-storage-plus"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c087ff98fb0475db4c2b5298a5fd12b2848d2854b39d1115d930ee6da24d1eed"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"schemars",
|
"schemars",
|
||||||
@@ -1322,16 +1311,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519-zebra"
|
name = "ed25519-zebra"
|
||||||
version = "2.2.0"
|
version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409"
|
checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"hex",
|
"hex",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.6.3",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1470,7 +1460,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"humantime-serde",
|
"humantime-serde",
|
||||||
@@ -2902,7 +2892,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.34.0",
|
"clap 2.34.0",
|
||||||
"client-core",
|
"client-core",
|
||||||
@@ -2936,7 +2926,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-gateway"
|
name = "nym-gateway"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -2982,7 +2972,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-mixnode"
|
name = "nym-mixnode"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bs58",
|
"bs58",
|
||||||
@@ -3020,7 +3010,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.34.0",
|
"clap 2.34.0",
|
||||||
"dirs",
|
"dirs",
|
||||||
@@ -3041,7 +3031,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.34.0",
|
"clap 2.34.0",
|
||||||
"client-core",
|
"client-core",
|
||||||
@@ -3076,7 +3066,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-validator-api"
|
name = "nym-validator-api"
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"attohttpc",
|
"attohttpc",
|
||||||
@@ -3683,15 +3673,6 @@ dependencies = [
|
|||||||
"uint",
|
"uint",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "primitives"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"cosmrs",
|
|
||||||
"cosmwasm-std",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -6008,7 +5989,6 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"network-defaults",
|
"network-defaults",
|
||||||
"primitives",
|
|
||||||
"prost",
|
"prost",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -6072,11 +6052,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vesting-contract"
|
name = "vesting-contract"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus 0.12.1",
|
"cw-storage-plus",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -6090,7 +6070,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus 0.11.1",
|
"cw-storage-plus",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ members = [
|
|||||||
"common/nymsphinx/params",
|
"common/nymsphinx/params",
|
||||||
"common/nymsphinx/types",
|
"common/nymsphinx/types",
|
||||||
"common/pemstore",
|
"common/pemstore",
|
||||||
"common/primitives",
|
|
||||||
"common/socks5/proxy-helpers",
|
"common/socks5/proxy-helpers",
|
||||||
"common/socks5/requests",
|
"common/socks5/requests",
|
||||||
"common/topology",
|
"common/topology",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "client-core"
|
name = "client-core"
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.56"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.56"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client-wasm"
|
name = "nym-client-wasm"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ url = { version = "2.2", features = ["serde"] }
|
|||||||
|
|
||||||
coconut-interface = { path = "../../coconut-interface" }
|
coconut-interface = { path = "../../coconut-interface" }
|
||||||
network-defaults = { path = "../../network-defaults" }
|
network-defaults = { path = "../../network-defaults" }
|
||||||
primitives = { path = "../../primitives" }
|
|
||||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
|
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
|
||||||
|
|
||||||
# required for nymd-client
|
# required for nymd-client
|
||||||
@@ -39,7 +38,7 @@ prost = { version = "0.9", default-features = false, optional = true }
|
|||||||
flate2 = { version = "1.0.20", optional = true }
|
flate2 = { version = "1.0.20", optional = true }
|
||||||
sha2 = { version = "0.9.5", optional = true }
|
sha2 = { version = "0.9.5", optional = true }
|
||||||
itertools = { version = "0.10", optional = true }
|
itertools = { version = "0.10", optional = true }
|
||||||
cosmwasm-std = { version = "1.0.0-beta3", optional = true }
|
cosmwasm-std = { version = "1.0.0-beta6", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ts-rs = "6.1.2"
|
ts-rs = "6.1.2"
|
||||||
|
|||||||
@@ -369,14 +369,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
|||||||
&self,
|
&self,
|
||||||
sender_address: &AccountId,
|
sender_address: &AccountId,
|
||||||
recipient_address: &AccountId,
|
recipient_address: &AccountId,
|
||||||
amount: Vec<primitives::Coin>,
|
amount: Vec<Coin>,
|
||||||
fee: Fee,
|
fee: Fee,
|
||||||
memo: impl Into<String> + Send + 'static,
|
memo: impl Into<String> + Send + 'static,
|
||||||
) -> Result<broadcast::tx_commit::Response, NymdError> {
|
) -> Result<broadcast::tx_commit::Response, NymdError> {
|
||||||
let send_msg = MsgSend {
|
let send_msg = MsgSend {
|
||||||
from_address: sender_address.clone(),
|
from_address: sender_address.clone(),
|
||||||
to_address: recipient_address.clone(),
|
to_address: recipient_address.clone(),
|
||||||
amount: primitives::coin::try_into(amount)?,
|
amount,
|
||||||
}
|
}
|
||||||
.to_any()
|
.to_any()
|
||||||
.map_err(|_| NymdError::SerializationError("MsgSend".to_owned()))?;
|
.map_err(|_| NymdError::SerializationError("MsgSend".to_owned()))?;
|
||||||
|
|||||||
@@ -108,9 +108,6 @@ pub enum NymdError {
|
|||||||
|
|
||||||
#[error("Abci query failed with code {0} - {1}")]
|
#[error("Abci query failed with code {0} - {1}")]
|
||||||
AbciError(u32, abci::Log),
|
AbciError(u32, abci::Log),
|
||||||
|
|
||||||
#[error("Failed to handle primitives")]
|
|
||||||
PrimitivesError(#[from] primitives::PrimitivesError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NymdError {
|
impl NymdError {
|
||||||
|
|||||||
@@ -589,6 +589,7 @@ impl<C> NymdClient<C> {
|
|||||||
&self,
|
&self,
|
||||||
mix_identity: IdentityKey,
|
mix_identity: IdentityKey,
|
||||||
delegator: &AccountId,
|
delegator: &AccountId,
|
||||||
|
proxy: Option<String>,
|
||||||
) -> Result<Delegation, NymdError>
|
) -> Result<Delegation, NymdError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync,
|
C: CosmWasmClient + Sync,
|
||||||
@@ -596,6 +597,7 @@ impl<C> NymdClient<C> {
|
|||||||
let request = QueryMsg::GetDelegationDetails {
|
let request = QueryMsg::GetDelegationDetails {
|
||||||
mix_identity,
|
mix_identity,
|
||||||
delegator: delegator.to_string(),
|
delegator: delegator.to_string(),
|
||||||
|
proxy,
|
||||||
};
|
};
|
||||||
self.client
|
self.client
|
||||||
.query_contract_smart(self.mixnet_contract_address()?, &request)
|
.query_contract_smart(self.mixnet_contract_address()?, &request)
|
||||||
@@ -606,7 +608,7 @@ impl<C> NymdClient<C> {
|
|||||||
pub async fn send(
|
pub async fn send(
|
||||||
&self,
|
&self,
|
||||||
recipient: &AccountId,
|
recipient: &AccountId,
|
||||||
amount: Vec<primitives::Coin>,
|
amount: Vec<CosmosCoin>,
|
||||||
memo: impl Into<String> + Send + 'static,
|
memo: impl Into<String> + Send + 'static,
|
||||||
) -> Result<broadcast::tx_commit::Response, NymdError>
|
) -> Result<broadcast::tx_commit::Response, NymdError>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
cosmwasm-std = "1.0.0-beta6"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
cosmwasm-std = "1.0.0-beta6"
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_repr = "0.1"
|
serde_repr = "0.1"
|
||||||
|
|||||||
@@ -9,6 +9,23 @@ use cosmwasm_std::{Coin, Uint128};
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
type OwnerAddressBytes = Vec<u8>;
|
||||||
|
type BlockHeight = u64;
|
||||||
|
|
||||||
|
pub fn generate_storage_key(address: &Addr, proxy: Option<&Addr>) -> Vec<u8> {
|
||||||
|
if let Some(proxy) = &proxy {
|
||||||
|
address
|
||||||
|
.as_bytes()
|
||||||
|
.iter()
|
||||||
|
.zip(proxy.as_bytes())
|
||||||
|
.map(|(x, y)| x ^ y)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
address.as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||||
pub struct Delegation {
|
pub struct Delegation {
|
||||||
@@ -19,12 +36,24 @@ pub struct Delegation {
|
|||||||
pub proxy: Option<Addr>, // proxy address used to delegate the funds on behalf of anouther address
|
pub proxy: Option<Addr>, // proxy address used to delegate the funds on behalf of anouther address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for Delegation {}
|
||||||
|
|
||||||
|
#[allow(clippy::derive_hash_xor_eq)]
|
||||||
|
impl Hash for Delegation {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.owner.hash(state);
|
||||||
|
self.node_identity.hash(state);
|
||||||
|
self.block_height.hash(state);
|
||||||
|
self.proxy.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Delegation {
|
impl Delegation {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
owner: Addr,
|
owner: Addr,
|
||||||
node_identity: IdentityKey,
|
node_identity: IdentityKey,
|
||||||
amount: Coin,
|
amount: Coin,
|
||||||
block_height: u64,
|
block_height: BlockHeight,
|
||||||
proxy: Option<Addr>,
|
proxy: Option<Addr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Delegation {
|
Delegation {
|
||||||
@@ -36,15 +65,30 @@ impl Delegation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: change that to use .joined_key() and return Vec<u8>
|
pub fn storage_key(&self) -> (IdentityKey, OwnerAddressBytes, BlockHeight) {
|
||||||
pub fn storage_key(&self) -> (IdentityKey, Vec<u8>, u64) {
|
|
||||||
(
|
(
|
||||||
self.node_identity(),
|
self.node_identity(),
|
||||||
self.owner().as_bytes().to_vec(),
|
self.proxy_storage_key(),
|
||||||
self.block_height(),
|
self.block_height(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn event_storage_key(&self) -> (OwnerAddressBytes, BlockHeight, IdentityKey) {
|
||||||
|
(
|
||||||
|
self.proxy_storage_key(),
|
||||||
|
self.block_height(),
|
||||||
|
self.node_identity(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy_storage_key(&self) -> OwnerAddressBytes {
|
||||||
|
generate_storage_key(&self.owner, self.proxy.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> Option<&Addr> {
|
||||||
|
self.proxy.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increment_amount(&mut self, amount: Uint128, at_height: Option<u64>) {
|
pub fn increment_amount(&mut self, amount: Uint128, at_height: Option<u64>) {
|
||||||
self.amount.amount += amount;
|
self.amount.amount += amount;
|
||||||
if let Some(at_height) = at_height {
|
if let Some(at_height) = at_height {
|
||||||
@@ -86,10 +130,10 @@ pub struct PagedMixDelegationsResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PagedMixDelegationsResponse {
|
impl PagedMixDelegationsResponse {
|
||||||
pub fn new(delegations: Vec<Delegation>, start_next_after: Option<(Addr, u64)>) -> Self {
|
pub fn new(delegations: Vec<Delegation>, start_next_after: Option<(String, u64)>) -> Self {
|
||||||
PagedMixDelegationsResponse {
|
PagedMixDelegationsResponse {
|
||||||
delegations,
|
delegations,
|
||||||
start_next_after: start_next_after.map(|(s, h)| (s.to_string(), h)),
|
start_next_after,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
mod delegation;
|
pub mod delegation;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
mod gateway;
|
mod gateway;
|
||||||
|
|||||||
@@ -78,6 +78,35 @@ impl PendingUndelegate {
|
|||||||
pub fn block_height(&self) -> u64 {
|
pub fn block_height(&self) -> u64 {
|
||||||
self.block_height
|
self.block_height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn proxy_storage_key(&self) -> Vec<u8> {
|
||||||
|
if let Some(proxy) = &self.proxy {
|
||||||
|
self.delegate()
|
||||||
|
.as_bytes()
|
||||||
|
.iter()
|
||||||
|
.zip(proxy.as_bytes())
|
||||||
|
.map(|(x, y)| x ^ y)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
self.delegate().as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn storage_key(&self) -> (IdentityKey, Vec<u8>) {
|
||||||
|
(self.mix_identity(), self.proxy_storage_key())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delegation_key(&self, block_height: u64) -> (IdentityKey, Vec<u8>, u64) {
|
||||||
|
(self.mix_identity(), self.proxy_storage_key(), block_height)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_storage_key(&self) -> (Vec<u8>, u64, IdentityKey) {
|
||||||
|
(
|
||||||
|
self.proxy_storage_key(),
|
||||||
|
self.block_height(),
|
||||||
|
self.mix_identity(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ pub enum ExecuteMsg {
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
|
GetAllDelegationKeys {},
|
||||||
|
DebugGetAllDelegationValues {},
|
||||||
GetContractVersion {},
|
GetContractVersion {},
|
||||||
GetMixNodes {
|
GetMixNodes {
|
||||||
limit: Option<u32>,
|
limit: Option<u32>,
|
||||||
@@ -137,6 +139,7 @@ pub enum QueryMsg {
|
|||||||
GetDelegationDetails {
|
GetDelegationDetails {
|
||||||
mix_identity: IdentityKey,
|
mix_identity: IdentityKey,
|
||||||
delegator: String,
|
delegator: String,
|
||||||
|
proxy: Option<String>,
|
||||||
},
|
},
|
||||||
LayerDistribution {},
|
LayerDistribution {},
|
||||||
GetRewardPool {},
|
GetRewardPool {},
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
cosmwasm-std = "1.0.0-beta6"
|
||||||
mixnet-contract-common = { path = "../mixnet-contract" }
|
mixnet-contract-common = { path = "../mixnet-contract" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
cw-storage-plus = "0.11.1"
|
cw-storage-plus = "0.13.1"
|
||||||
config = { path = "../../config" }
|
config = { path = "../../config" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "primitives"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
cosmrs = { version = "0.4.1", features = ["rpc", "bip32", "cosmwasm"] }
|
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
|
||||||
thiserror = "1.0"
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::error::PrimitivesError;
|
|
||||||
use core::fmt;
|
|
||||||
use cosmwasm_std::Uint128;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
/// Common Coin type for the backend.
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct Coin {
|
|
||||||
pub amount: Uint128,
|
|
||||||
pub denom: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Coin {
|
|
||||||
pub fn new(amount: u128, denom: impl Into<String>) -> Coin {
|
|
||||||
Coin {
|
|
||||||
amount: Uint128::new(amount),
|
|
||||||
denom: denom.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Coin {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}{}", self.amount, self.denom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<cosmrs::Coin> for Coin {
|
|
||||||
type Error = PrimitivesError;
|
|
||||||
|
|
||||||
fn try_from(cosmos_coin: cosmrs::Coin) -> Result<Self, Self::Error> {
|
|
||||||
Ok(Self {
|
|
||||||
amount: cosmos_coin.amount.to_string().as_str().try_into()?,
|
|
||||||
denom: cosmos_coin.denom.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Coin> for cosmrs::Coin {
|
|
||||||
type Error = PrimitivesError;
|
|
||||||
|
|
||||||
fn try_from(coin: Coin) -> Result<Self, Self::Error> {
|
|
||||||
Ok(Self {
|
|
||||||
denom: cosmrs::Denom::from_str(&coin.denom)?,
|
|
||||||
amount: cosmrs::Decimal::from_str(&coin.amount.to_string())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn try_into(coins: Vec<Coin>) -> Result<Vec<cosmrs::Coin>, PrimitivesError> {
|
|
||||||
coins.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into(coins: Vec<Coin>) -> Vec<cosmwasm_std::Coin> {
|
|
||||||
coins.into_iter().map(Into::into).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<cosmwasm_std::Coin> for Coin {
|
|
||||||
fn from(cosmwasm_coin: cosmwasm_std::Coin) -> Self {
|
|
||||||
Self {
|
|
||||||
amount: cosmwasm_coin.amount,
|
|
||||||
denom: cosmwasm_coin.denom,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Coin> for cosmwasm_std::Coin {
|
|
||||||
fn from(coin: Coin) -> Self {
|
|
||||||
Self {
|
|
||||||
amount: coin.amount,
|
|
||||||
denom: coin.denom,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn convert_to_and_from_cosmwasm_coin() {
|
|
||||||
let coin = Coin::new(42, "ucoin");
|
|
||||||
let cosmwasm_coin: cosmwasm_std::Coin = coin.clone().into();
|
|
||||||
assert_eq!(coin, Coin::from(cosmwasm_coin));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn convert_to_and_from_cosmos_coin() {
|
|
||||||
let coin = Coin::new(42, "ucoin");
|
|
||||||
let cosmos_coin: cosmrs::Coin = coin.clone().try_into().unwrap();
|
|
||||||
assert_eq!(coin, Coin::try_from(cosmos_coin).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
// WIP(JON): more tests
|
|
||||||
// Especially converting from cosmrs::Coin
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum PrimitivesError {
|
|
||||||
#[error("{source}")]
|
|
||||||
CosmwasmError {
|
|
||||||
#[from]
|
|
||||||
source: cosmwasm_std::StdError,
|
|
||||||
},
|
|
||||||
#[error("{source}")]
|
|
||||||
CosmrsError {
|
|
||||||
#[from]
|
|
||||||
source: cosmrs::ErrorReport,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
pub mod coin;
|
|
||||||
mod error;
|
|
||||||
|
|
||||||
pub use error::PrimitivesError;
|
|
||||||
pub use coin::Coin;
|
|
||||||
Generated
+22
-31
@@ -41,7 +41,7 @@ checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bandwidth-claim"
|
name = "bandwidth-claim"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bandwidth-claim-contract",
|
"bandwidth-claim-contract",
|
||||||
"config",
|
"config",
|
||||||
@@ -218,22 +218,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-crypto"
|
name = "cosmwasm-crypto"
|
||||||
version = "1.0.0-beta6"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dddc1443004c6340e55ca66d98e9d2f1a44aadf4ce2bed2c4f29baa8a15e7b7"
|
checksum = "88c2565b1e73a816fb659ef4838fc356143fbd35f43c48a51d2d7d4e5d6679d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"ed25519-zebra",
|
"ed25519-zebra",
|
||||||
"k256",
|
"k256",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.6.3",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-derive"
|
name = "cosmwasm-derive"
|
||||||
version = "1.0.0-beta6"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe4f0f10f165b8bcc558a13cddb498140960544519aa0581532c766dd80b5598"
|
checksum = "fa89fcdf8dbbe0088e663d0a814aa7368e7ebe8fb045a3a150fb5fdc2ffe3b45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
@@ -250,9 +250,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-std"
|
name = "cosmwasm-std"
|
||||||
version = "1.0.0-beta6"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f0f3145097b692b2d95fa5d2c7c6fdd60f193ccc709857e7e1987a608725300"
|
checksum = "bcb8f99a61d0b9069e1afc80a4ffea87dcc3523edd992080923870b13a677da0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"cosmwasm-crypto",
|
"cosmwasm-crypto",
|
||||||
@@ -267,9 +267,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-storage"
|
name = "cosmwasm-storage"
|
||||||
version = "1.0.0-beta3"
|
version = "1.0.0-beta7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4a4e55f0d64fed54cd2202301b8d466af8de044589247dabd77a4222f52f749"
|
checksum = "07f856099c824aa8f2488e62d1da3fc06383d3fdbc764573595f451be43441a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -360,20 +360,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cw-storage-plus"
|
name = "cw-storage-plus"
|
||||||
version = "0.11.1"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261"
|
checksum = "5e8b7f9a758c030d375520df947323c052704f784561fc28dcaab4f988c50a30"
|
||||||
dependencies = [
|
|
||||||
"cosmwasm-std",
|
|
||||||
"schemars",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cw-storage-plus"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c087ff98fb0475db4c2b5298a5fd12b2848d2854b39d1115d930ee6da24d1eed"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"schemars",
|
"schemars",
|
||||||
@@ -450,16 +439,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519-zebra"
|
name = "ed25519-zebra"
|
||||||
version = "2.2.0"
|
version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409"
|
checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"hex",
|
"hex",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.6.3",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -820,7 +810,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mixnet-contract"
|
name = "mixnet-contract"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"az",
|
"az",
|
||||||
"bs58",
|
"bs58",
|
||||||
@@ -829,8 +819,9 @@ dependencies = [
|
|||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cosmwasm-storage",
|
"cosmwasm-storage",
|
||||||
"crypto",
|
"crypto",
|
||||||
"cw-storage-plus 0.12.1",
|
"cw-storage-plus",
|
||||||
"fixed",
|
"fixed",
|
||||||
|
"hex",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
@@ -1527,11 +1518,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vesting-contract"
|
name = "vesting-contract"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus 0.12.1",
|
"cw-storage-plus",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1545,7 +1536,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus 0.11.1",
|
"cw-storage-plus",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bandwidth-claim"
|
name = "bandwidth-claim"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -14,8 +14,8 @@ config = { path = "../../common/config"}
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
|
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
|
||||||
|
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
cosmwasm-std = "1.0.0-beta6"
|
||||||
cosmwasm-storage = "1.0.0-beta3"
|
cosmwasm-storage = "1.0.0-beta6"
|
||||||
|
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mixnet-contract"
|
name = "mixnet-contract"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@ mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-
|
|||||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||||
config = { path = "../../common/config"}
|
config = { path = "../../common/config"}
|
||||||
|
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
cosmwasm-std = "1.0.0-beta6"
|
||||||
cosmwasm-storage = "1.0.0-beta3"
|
cosmwasm-storage = "1.0.0-beta6"
|
||||||
cw-storage-plus = "0.12.1"
|
cw-storage-plus = "0.13.1"
|
||||||
|
|
||||||
az = "1.2.0"
|
az = "1.2.0"
|
||||||
bs58 = "0.4.0"
|
bs58 = "0.4.0"
|
||||||
@@ -30,6 +30,7 @@ schemars = "0.8"
|
|||||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||||
thiserror = { version = "1.0.23" }
|
thiserror = { version = "1.0.23" }
|
||||||
time = { version = "0.3", features = ["macros"] }
|
time = { version = "0.3", features = ["macros"] }
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cosmwasm-schema = "1.0.0-beta3"
|
cosmwasm-schema = "1.0.0-beta3"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ use cosmwasm_std::{
|
|||||||
entry_point, to_binary, Addr, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, Uint128,
|
entry_point, to_binary, Addr, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, Uint128,
|
||||||
};
|
};
|
||||||
use mixnet_contract_common::{
|
use mixnet_contract_common::{
|
||||||
ContractStateParams, Delegation, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
|
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
|
||||||
};
|
};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
@@ -312,11 +312,13 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
|||||||
QueryMsg::GetDelegationDetails {
|
QueryMsg::GetDelegationDetails {
|
||||||
mix_identity,
|
mix_identity,
|
||||||
delegator,
|
delegator,
|
||||||
|
proxy,
|
||||||
} => to_binary(&query_mixnode_delegation(
|
} => to_binary(&query_mixnode_delegation(
|
||||||
deps.storage,
|
deps.storage,
|
||||||
deps.api,
|
deps.api,
|
||||||
mix_identity,
|
mix_identity,
|
||||||
delegator,
|
delegator,
|
||||||
|
proxy,
|
||||||
)?),
|
)?),
|
||||||
QueryMsg::GetRewardPool {} => to_binary(&query_reward_pool(deps)?),
|
QueryMsg::GetRewardPool {} => to_binary(&query_reward_pool(deps)?),
|
||||||
QueryMsg::GetCirculatingSupply {} => to_binary(&query_circulating_supply(deps)?),
|
QueryMsg::GetCirculatingSupply {} => to_binary(&query_circulating_supply(deps)?),
|
||||||
@@ -363,66 +365,19 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
|||||||
QueryMsg::GetPendingDelegationEvents { owner_address } => to_binary(
|
QueryMsg::GetPendingDelegationEvents { owner_address } => to_binary(
|
||||||
&query_pending_delegation_events(deps.storage, owner_address)?,
|
&query_pending_delegation_events(deps.storage, owner_address)?,
|
||||||
),
|
),
|
||||||
|
QueryMsg::GetAllDelegationKeys {} => to_binary(
|
||||||
|
&crate::delegations::queries::query_all_delegation_keys(deps.storage)?,
|
||||||
|
),
|
||||||
|
QueryMsg::DebugGetAllDelegationValues {} => to_binary(
|
||||||
|
&crate::delegations::queries::debug_query_all_delegation_values(deps.storage)?,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(query_res?)
|
Ok(query_res?)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MIGRATE OLD DELEGATION STORAGE
|
|
||||||
// applied on QAnet
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn migrate_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
|
||||||
use crate::delegations::storage::{
|
|
||||||
DelegationIndex, DELEGATION_MIXNODE_IDX_NAMESPACE, DELEGATION_OWNER_IDX_NAMESPACE,
|
|
||||||
DELEGATION_PK_NAMESPACE,
|
|
||||||
};
|
|
||||||
use cosmwasm_std::Order;
|
|
||||||
use cw_storage_plus::{IndexedMap, MultiIndex};
|
|
||||||
|
|
||||||
type PrimaryKey = Vec<u8>;
|
|
||||||
|
|
||||||
fn old_delegations<'a>() -> IndexedMap<'a, PrimaryKey, Delegation, DelegationIndex<'a>> {
|
|
||||||
let indexes = DelegationIndex {
|
|
||||||
owner: MultiIndex::new(
|
|
||||||
|d| d.owner.clone(),
|
|
||||||
DELEGATION_PK_NAMESPACE,
|
|
||||||
DELEGATION_OWNER_IDX_NAMESPACE,
|
|
||||||
),
|
|
||||||
mixnode: MultiIndex::new(
|
|
||||||
|d| d.node_identity.clone(),
|
|
||||||
DELEGATION_PK_NAMESPACE,
|
|
||||||
DELEGATION_MIXNODE_IDX_NAMESPACE,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
IndexedMap::new(DELEGATION_PK_NAMESPACE, indexes)
|
|
||||||
}
|
|
||||||
|
|
||||||
let old_delegations = old_delegations()
|
|
||||||
.range(deps.storage, None, None, Order::Ascending)
|
|
||||||
.filter_map(|r| r.ok())
|
|
||||||
.map(|(_key, delegation)| delegation)
|
|
||||||
.collect::<Vec<Delegation>>();
|
|
||||||
|
|
||||||
for delegation in old_delegations {
|
|
||||||
crate::delegations::storage::delegations().save(
|
|
||||||
deps.storage,
|
|
||||||
(
|
|
||||||
delegation.node_identity(),
|
|
||||||
delegation.owner().as_bytes().to_vec(),
|
|
||||||
delegation.block_height(),
|
|
||||||
),
|
|
||||||
&delegation,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[entry_point]
|
#[entry_point]
|
||||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||||
// TODO: Uncomment mainnet
|
|
||||||
// migrate_delegations(deps)?;
|
|
||||||
|
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,14 +43,18 @@ pub(crate) fn query_delegator_delegations_paged(
|
|||||||
.idx
|
.idx
|
||||||
.owner
|
.owner
|
||||||
.prefix(validated_owner)
|
.prefix(validated_owner)
|
||||||
.range(deps.storage, start, None, Order::Ascending)
|
.range_raw(deps.storage, start, None, Order::Ascending)
|
||||||
.take(limit)
|
.take(limit)
|
||||||
.map(|record| record.map(|r| r.1))
|
.map(|record| record.map(|r| r.1))
|
||||||
.collect::<StdResult<Vec<_>>>()?;
|
.collect::<StdResult<Vec<_>>>()?;
|
||||||
|
|
||||||
let start_next_after = delegations
|
let start_next_after = if delegations.len() < limit {
|
||||||
.last()
|
None
|
||||||
.map(|delegation| delegation.node_identity());
|
} else {
|
||||||
|
delegations
|
||||||
|
.last()
|
||||||
|
.map(|delegation| delegation.node_identity())
|
||||||
|
};
|
||||||
|
|
||||||
Ok(PagedDelegatorDelegationsResponse::new(
|
Ok(PagedDelegatorDelegationsResponse::new(
|
||||||
delegations,
|
delegations,
|
||||||
@@ -58,17 +62,70 @@ pub(crate) fn query_delegator_delegations_paged(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn query_all_delegation_keys(storage: &dyn Storage) -> Result<Vec<String>, ContractError> {
|
||||||
|
Ok(storage::delegations()
|
||||||
|
.keys_raw(storage, None, None, Order::Ascending)
|
||||||
|
.map(hex::encode)
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
// This should only be exposed directly on the contract via nymd binary, not through the nymd clients
|
||||||
|
pub fn debug_query_all_delegation_values(
|
||||||
|
storage: &dyn Storage,
|
||||||
|
) -> Result<HashSet<Delegation>, ContractError> {
|
||||||
|
use crate::delegations::storage::{
|
||||||
|
DelegationIndex, DELEGATION_MIXNODE_IDX_NAMESPACE, DELEGATION_OWNER_IDX_NAMESPACE,
|
||||||
|
DELEGATION_PK_NAMESPACE,
|
||||||
|
};
|
||||||
|
|
||||||
|
use cw_storage_plus::{IndexedMap, MultiIndex};
|
||||||
|
|
||||||
|
type PrimaryKey = Vec<u8>;
|
||||||
|
|
||||||
|
fn all_delegations<'a>() -> IndexedMap<'a, PrimaryKey, Delegation, DelegationIndex<'a>> {
|
||||||
|
let indexes = DelegationIndex {
|
||||||
|
owner: MultiIndex::new(
|
||||||
|
|d| d.owner.clone(),
|
||||||
|
DELEGATION_PK_NAMESPACE,
|
||||||
|
DELEGATION_OWNER_IDX_NAMESPACE,
|
||||||
|
),
|
||||||
|
mixnode: MultiIndex::new(
|
||||||
|
|d| d.node_identity.clone(),
|
||||||
|
DELEGATION_PK_NAMESPACE,
|
||||||
|
DELEGATION_MIXNODE_IDX_NAMESPACE,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
IndexedMap::new(DELEGATION_PK_NAMESPACE, indexes)
|
||||||
|
}
|
||||||
|
|
||||||
|
let all_delegations = all_delegations()
|
||||||
|
.range(storage, None, None, Order::Ascending)
|
||||||
|
.filter_map(|r| r.ok())
|
||||||
|
.map(|(_key, delegation)| delegation)
|
||||||
|
.collect::<HashSet<Delegation>>();
|
||||||
|
|
||||||
|
Ok(all_delegations)
|
||||||
|
}
|
||||||
|
|
||||||
// queries for delegation value of given address for particular node
|
// queries for delegation value of given address for particular node
|
||||||
pub(crate) fn query_mixnode_delegation(
|
pub(crate) fn query_mixnode_delegation(
|
||||||
storage: &dyn Storage,
|
storage: &dyn Storage,
|
||||||
api: &dyn Api,
|
api: &dyn Api,
|
||||||
mix_identity: IdentityKey,
|
mix_identity: IdentityKey,
|
||||||
delegator: String,
|
delegator: String,
|
||||||
|
proxy: Option<String>,
|
||||||
) -> Result<Vec<Delegation>, ContractError> {
|
) -> Result<Vec<Delegation>, ContractError> {
|
||||||
let validated_delegator = api.addr_validate(&delegator)?;
|
let validated_delegator = api.addr_validate(&delegator)?;
|
||||||
|
let proxy = proxy.map(|p| api.addr_validate(&p).expect("Invalid proxy address"));
|
||||||
let storage_key = (
|
let storage_key = (
|
||||||
mix_identity.clone(),
|
mix_identity.clone(),
|
||||||
validated_delegator.as_bytes().to_vec(),
|
mixnet_contract_common::delegation::generate_storage_key(
|
||||||
|
&validated_delegator,
|
||||||
|
proxy.as_ref(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let delegations = storage::delegations()
|
let delegations = storage::delegations()
|
||||||
@@ -99,21 +156,30 @@ pub(crate) fn query_mixnode_delegations_paged(
|
|||||||
.min(storage::DELEGATION_PAGE_MAX_LIMIT) as usize;
|
.min(storage::DELEGATION_PAGE_MAX_LIMIT) as usize;
|
||||||
|
|
||||||
let start = start_after.map(|(addr, height)| {
|
let start = start_after.map(|(addr, height)| {
|
||||||
Bound::ExclusiveRaw((mix_identity.clone(), addr.as_bytes(), height).joined_key())
|
Bound::exclusive((
|
||||||
|
hex::decode(addr).expect("Could not hex decode proxy_storage_key"),
|
||||||
|
height,
|
||||||
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
let delegations = storage::delegations()
|
let delegations = storage::delegations()
|
||||||
.idx
|
.sub_prefix(mix_identity)
|
||||||
.mixnode
|
|
||||||
.prefix(mix_identity)
|
|
||||||
.range(deps.storage, start, None, Order::Ascending)
|
.range(deps.storage, start, None, Order::Ascending)
|
||||||
.take(limit)
|
.take(limit)
|
||||||
.map(|record| record.map(|r| r.1))
|
.filter_map(|r| r.ok())
|
||||||
.collect::<StdResult<Vec<_>>>()?;
|
.map(|record| record.1)
|
||||||
|
.collect::<Vec<Delegation>>();
|
||||||
|
|
||||||
let start_next_after = delegations
|
let start_next_after = if delegations.len() < limit {
|
||||||
.last()
|
None
|
||||||
.map(|delegation| (delegation.owner(), delegation.block_height()));
|
} else {
|
||||||
|
delegations.last().map(|delegation| {
|
||||||
|
(
|
||||||
|
hex::encode(delegation.proxy_storage_key()),
|
||||||
|
delegation.block_height(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
Ok(PagedMixDelegationsResponse::new(
|
Ok(PagedMixDelegationsResponse::new(
|
||||||
delegations,
|
delegations,
|
||||||
@@ -127,18 +193,22 @@ pub(crate) mod tests {
|
|||||||
use crate::support::tests::test_helpers;
|
use crate::support::tests::test_helpers;
|
||||||
use config::defaults::DENOM;
|
use config::defaults::DENOM;
|
||||||
use cosmwasm_std::{coin, Addr, Storage};
|
use cosmwasm_std::{coin, Addr, Storage};
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
pub fn store_n_mix_delegations(n: u32, storage: &mut dyn Storage, node_identity: &str) {
|
pub fn store_n_mix_delegations(n: u32, storage: &mut dyn Storage, node_identity: &str) {
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let address = format!("address{}", i);
|
let address = format!("address{}", i);
|
||||||
test_helpers::save_dummy_delegation(storage, node_identity, address);
|
test_helpers::save_dummy_delegation(storage, node_identity, address, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod querying_for_mixnode_delegations_paged {
|
mod querying_for_mixnode_delegations_paged {
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use mixnet_contract_common::IdentityKey;
|
use mixnet_contract_common::IdentityKey;
|
||||||
|
use rand::{distributions::Alphanumeric, SeedableRng};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn retrieval_obeys_limits() {
|
fn retrieval_obeys_limits() {
|
||||||
@@ -203,39 +273,37 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pagination_works() {
|
fn pagination_works() {
|
||||||
|
let dummy_seed = [42u8; 32];
|
||||||
|
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||||
|
|
||||||
let mut deps = test_helpers::init_contract();
|
let mut deps = test_helpers::init_contract();
|
||||||
let node_identity: IdentityKey = "foo".into();
|
let node_identity: IdentityKey = "foo".into();
|
||||||
let node_identity2: IdentityKey = "bar".into();
|
|
||||||
|
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "100");
|
let mut delegation_test_data = vec![];
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity2, "100");
|
let mut returned_delegation_data = HashSet::new();
|
||||||
|
|
||||||
let per_page = 2;
|
// Crete a bunch of randomly ordered (in storage) delegations
|
||||||
let page1 = query_mixnode_delegations_paged(
|
for _ in 0..200 {
|
||||||
deps.as_ref(),
|
delegation_test_data.push((
|
||||||
node_identity.clone(),
|
rng.clone()
|
||||||
None,
|
.sample_iter(&Alphanumeric)
|
||||||
Option::from(per_page),
|
.take(30)
|
||||||
)
|
.map(char::from)
|
||||||
.unwrap();
|
.collect::<String>(),
|
||||||
|
rng.gen::<u32>() as u64,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// page should have 1 result on it
|
for (address, block_height) in delegation_test_data.iter() {
|
||||||
assert_eq!(1, page1.delegations.len());
|
test_helpers::save_dummy_delegation(
|
||||||
|
&mut deps.storage,
|
||||||
|
&node_identity,
|
||||||
|
address,
|
||||||
|
*block_height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// save another
|
let per_page = 100;
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "200");
|
|
||||||
|
|
||||||
// page1 should have 2 results on it
|
|
||||||
let page1 = query_mixnode_delegations_paged(
|
|
||||||
deps.as_ref(),
|
|
||||||
node_identity.clone(),
|
|
||||||
None,
|
|
||||||
Option::from(per_page),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(2, page1.delegations.len());
|
|
||||||
|
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "300");
|
|
||||||
|
|
||||||
// page1 still has 2 results
|
// page1 still has 2 results
|
||||||
let page1 = query_mixnode_delegations_paged(
|
let page1 = query_mixnode_delegations_paged(
|
||||||
@@ -245,10 +313,20 @@ pub(crate) mod tests {
|
|||||||
Option::from(per_page),
|
Option::from(per_page),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{:?}", page1);
|
|
||||||
let start_after = page1.start_next_after.unwrap();
|
let start_after = page1.start_next_after.unwrap();
|
||||||
assert_eq!(2, page1.delegations.len());
|
assert_eq!(100, page1.delegations.len());
|
||||||
assert_eq!(("200".to_string(), 12345), start_after);
|
assert_eq!(
|
||||||
|
((
|
||||||
|
"5874735a724c52587679656777795a446a754a746c59694735423165694a".to_string(),
|
||||||
|
1594717548
|
||||||
|
)),
|
||||||
|
start_after
|
||||||
|
);
|
||||||
|
|
||||||
|
for delegation in page1.delegations {
|
||||||
|
returned_delegation_data.insert(delegation.owner().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
// retrieving the next page should start after the last key on this page
|
// retrieving the next page should start after the last key on this page
|
||||||
|
|
||||||
@@ -259,37 +337,33 @@ pub(crate) mod tests {
|
|||||||
Option::from(per_page),
|
Option::from(per_page),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{:?}", page2);
|
|
||||||
assert_eq!(1, page2.delegations.len());
|
|
||||||
assert_eq!(page2.delegations.last().unwrap().owner(), "300");
|
|
||||||
|
|
||||||
// save another one
|
let start_after = page2.start_next_after.unwrap();
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "400");
|
assert_eq!(
|
||||||
|
(
|
||||||
|
"7a6b48546c63674f57417948384e6f494a326c6b5a63767668597346696b".to_string(),
|
||||||
|
3448133410
|
||||||
|
),
|
||||||
|
start_after
|
||||||
|
);
|
||||||
|
|
||||||
let page2 = query_mixnode_delegations_paged(
|
for delegation in page2.delegations {
|
||||||
|
returned_delegation_data.insert(delegation.owner().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let page3 = query_mixnode_delegations_paged(
|
||||||
deps.as_ref(),
|
deps.as_ref(),
|
||||||
node_identity.clone(),
|
node_identity.clone(),
|
||||||
Option::from(start_after),
|
Option::from(start_after),
|
||||||
Option::from(per_page),
|
Option::from(per_page),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// println!("{:?}", page2);
|
|
||||||
|
|
||||||
// now we have 2 pages, with 2 results on the second page
|
|
||||||
assert_eq!(2, page2.delegations.len());
|
|
||||||
assert_eq!(page2.delegations.last().unwrap().owner(), "400");
|
|
||||||
|
|
||||||
// Should be empty
|
|
||||||
let page3 = query_mixnode_delegations_paged(
|
|
||||||
deps.as_ref(),
|
|
||||||
node_identity,
|
|
||||||
page2.start_next_after,
|
|
||||||
Option::from(per_page),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(page3.delegations.is_empty());
|
|
||||||
assert!(page3.start_next_after.is_none());
|
assert!(page3.start_next_after.is_none());
|
||||||
|
|
||||||
|
for delegation in delegation_test_data {
|
||||||
|
assert!(returned_delegation_data.contains(&*delegation.0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +391,8 @@ pub(crate) mod tests {
|
|||||||
&deps.storage,
|
&deps.storage,
|
||||||
&deps.api,
|
&deps.api,
|
||||||
node_identity,
|
node_identity,
|
||||||
delegation_owner.to_string()
|
delegation_owner.to_string(),
|
||||||
|
None
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -340,7 +415,8 @@ pub(crate) mod tests {
|
|||||||
&deps.storage,
|
&deps.storage,
|
||||||
&deps.api,
|
&deps.api,
|
||||||
node_identity1.clone(),
|
node_identity1.clone(),
|
||||||
delegation_owner1.to_string()
|
delegation_owner1.to_string(),
|
||||||
|
None
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -366,7 +442,8 @@ pub(crate) mod tests {
|
|||||||
&deps.storage,
|
&deps.storage,
|
||||||
&deps.api,
|
&deps.api,
|
||||||
node_identity1.clone(),
|
node_identity1.clone(),
|
||||||
delegation_owner1.to_string()
|
delegation_owner1.to_string(),
|
||||||
|
None
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -392,7 +469,8 @@ pub(crate) mod tests {
|
|||||||
&deps.storage,
|
&deps.storage,
|
||||||
&deps.api,
|
&deps.api,
|
||||||
node_identity1,
|
node_identity1,
|
||||||
delegation_owner1.to_string()
|
delegation_owner1.to_string(),
|
||||||
|
None
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -404,7 +482,7 @@ pub(crate) mod tests {
|
|||||||
fn store_n_reverse_delegations(n: u32, storage: &mut dyn Storage, delegation_owner: &str) {
|
fn store_n_reverse_delegations(n: u32, storage: &mut dyn Storage, delegation_owner: &str) {
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let node_identity = format!("node{}", i);
|
let node_identity = format!("node{}", i);
|
||||||
test_helpers::save_dummy_delegation(storage, node_identity, delegation_owner);
|
test_helpers::save_dummy_delegation(storage, node_identity, delegation_owner, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,9 +553,18 @@ pub(crate) mod tests {
|
|||||||
let mut deps = test_helpers::init_contract();
|
let mut deps = test_helpers::init_contract();
|
||||||
let delegation_owner = "bar".to_string();
|
let delegation_owner = "bar".to_string();
|
||||||
|
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, "100", &delegation_owner);
|
for j in 0..20 {
|
||||||
|
for i in 0..10 {
|
||||||
|
test_helpers::save_dummy_delegation(
|
||||||
|
&mut deps.storage,
|
||||||
|
format!("{}-{}", j, i),
|
||||||
|
delegation_owner.clone(),
|
||||||
|
i,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let per_page = 2;
|
let per_page = 100;
|
||||||
let page1 = query_delegator_delegations_paged(
|
let page1 = query_delegator_delegations_paged(
|
||||||
deps.as_ref(),
|
deps.as_ref(),
|
||||||
delegation_owner.clone(),
|
delegation_owner.clone(),
|
||||||
@@ -486,60 +573,30 @@ pub(crate) mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// page should have 1 result on it
|
let start_after = page1.start_next_after.unwrap();
|
||||||
assert_eq!(1, page1.delegations.len());
|
assert_eq!(per_page as usize, page1.delegations.len());
|
||||||
|
assert_eq!(start_after, "9-9".to_string());
|
||||||
|
|
||||||
// save another
|
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, "200", &delegation_owner);
|
|
||||||
|
|
||||||
// page1 should have 2 results on it
|
|
||||||
let page1 = query_delegator_delegations_paged(
|
|
||||||
deps.as_ref(),
|
|
||||||
delegation_owner.clone(),
|
|
||||||
None,
|
|
||||||
Option::from(per_page),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(2, page1.delegations.len());
|
|
||||||
|
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, "300", &delegation_owner);
|
|
||||||
|
|
||||||
// page1 still has 2 results
|
|
||||||
let page1 = query_delegator_delegations_paged(
|
|
||||||
deps.as_ref(),
|
|
||||||
delegation_owner.clone(),
|
|
||||||
None,
|
|
||||||
Option::from(per_page),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(2, page1.delegations.len());
|
|
||||||
|
|
||||||
// retrieving the next page should start after the last key on this page
|
|
||||||
let start_after: IdentityKey = page1.start_next_after.unwrap();
|
|
||||||
let page2 = query_delegator_delegations_paged(
|
let page2 = query_delegator_delegations_paged(
|
||||||
deps.as_ref(),
|
deps.as_ref(),
|
||||||
delegation_owner.clone(),
|
delegation_owner.clone(),
|
||||||
Option::from(start_after),
|
Some(start_after),
|
||||||
Option::from(per_page),
|
Option::from(per_page),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(1, page2.delegations.len());
|
let start_after = page2.start_next_after.unwrap();
|
||||||
|
assert_eq!(start_after, "19-9".to_string());
|
||||||
|
|
||||||
// save another one
|
let page3 = query_delegator_delegations_paged(
|
||||||
test_helpers::save_dummy_delegation(&mut deps.storage, "400", &delegation_owner);
|
|
||||||
|
|
||||||
let start_after = String::from("2");
|
|
||||||
let page2 = query_delegator_delegations_paged(
|
|
||||||
deps.as_ref(),
|
deps.as_ref(),
|
||||||
delegation_owner,
|
delegation_owner.clone(),
|
||||||
Option::from(start_after),
|
Some(start_after),
|
||||||
Option::from(per_page),
|
Option::from(per_page),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// now we have 2 pages, with 2 results on the second page
|
assert!(page3.start_next_after.is_none());
|
||||||
assert_eq!(2, page2.delegations.len());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ type OwnerAddress = Vec<u8>;
|
|||||||
type PrimaryKey = (IdentityKey, OwnerAddress, BlockHeight);
|
type PrimaryKey = (IdentityKey, OwnerAddress, BlockHeight);
|
||||||
|
|
||||||
pub(crate) struct DelegationIndex<'a> {
|
pub(crate) struct DelegationIndex<'a> {
|
||||||
pub(crate) owner: MultiIndex<'a, Addr, Delegation>,
|
pub(crate) owner: MultiIndex<'a, Addr, Delegation, PrimaryKey>,
|
||||||
|
|
||||||
pub(crate) mixnode: MultiIndex<'a, IdentityKey, Delegation>,
|
pub(crate) mixnode: MultiIndex<'a, IdentityKey, Delegation, PrimaryKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IndexList<Delegation> for DelegationIndex<'a> {
|
impl<'a> IndexList<Delegation> for DelegationIndex<'a> {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use super::storage::{self, PENDING_DELEGATION_EVENTS};
|
|||||||
use crate::error::ContractError;
|
use crate::error::ContractError;
|
||||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||||
use crate::mixnodes::storage as mixnodes_storage;
|
use crate::mixnodes::storage as mixnodes_storage;
|
||||||
use crate::support::helpers::generate_storage_key;
|
|
||||||
use config::defaults::DENOM;
|
use config::defaults::DENOM;
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order,
|
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order,
|
||||||
@@ -192,19 +191,18 @@ pub(crate) fn _try_delegate_to_mixnode(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let maybe_proxy_storage = generate_storage_key(&delegate, proxy.as_ref());
|
let delegation = Delegation::new(
|
||||||
let storage_key = (maybe_proxy_storage, block_height, mix_identity.to_string());
|
delegate.to_owned(),
|
||||||
|
mix_identity.to_string(),
|
||||||
|
amount.clone(),
|
||||||
|
block_height,
|
||||||
|
proxy.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
storage::PENDING_DELEGATION_EVENTS.save(
|
storage::PENDING_DELEGATION_EVENTS.save(
|
||||||
storage,
|
storage,
|
||||||
storage_key,
|
delegation.event_storage_key(),
|
||||||
&DelegationEvent::Delegate(Delegation::new(
|
&DelegationEvent::Delegate(delegation),
|
||||||
delegate.to_owned(),
|
|
||||||
mix_identity.to_string(),
|
|
||||||
amount.clone(),
|
|
||||||
block_height,
|
|
||||||
proxy.clone(),
|
|
||||||
)),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Response::new().add_event(new_pending_delegation_event(
|
Ok(Response::new().add_event(new_pending_delegation_event(
|
||||||
@@ -246,17 +244,9 @@ pub(crate) fn try_reconcile_undelegation(
|
|||||||
pending_undelegate: &PendingUndelegate,
|
pending_undelegate: &PendingUndelegate,
|
||||||
) -> Result<ReconcileUndelegateResponse, ContractError> {
|
) -> Result<ReconcileUndelegateResponse, ContractError> {
|
||||||
let delegation_map = storage::delegations();
|
let delegation_map = storage::delegations();
|
||||||
let maybe_proxy_storage = generate_storage_key(
|
|
||||||
&pending_undelegate.delegate(),
|
|
||||||
pending_undelegate.proxy().as_ref(),
|
|
||||||
);
|
|
||||||
let storage_key = (
|
|
||||||
pending_undelegate.mix_identity(),
|
|
||||||
maybe_proxy_storage.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let any_delegations = delegation_map
|
let any_delegations = delegation_map
|
||||||
.prefix(storage_key.clone())
|
.prefix(pending_undelegate.storage_key())
|
||||||
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
|
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
|
||||||
.filter_map(|v| v.ok())
|
.filter_map(|v| v.ok())
|
||||||
.next()
|
.next()
|
||||||
@@ -287,7 +277,7 @@ pub(crate) fn try_reconcile_undelegation(
|
|||||||
|
|
||||||
// Might want to introduce paging here
|
// Might want to introduce paging here
|
||||||
let delegation_heights = delegation_map
|
let delegation_heights = delegation_map
|
||||||
.prefix(storage_key)
|
.prefix(pending_undelegate.storage_key())
|
||||||
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
|
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
|
||||||
.filter_map(|v| v.ok())
|
.filter_map(|v| v.ok())
|
||||||
.collect::<Vec<u64>>();
|
.collect::<Vec<u64>>();
|
||||||
@@ -317,14 +307,15 @@ pub(crate) fn try_reconcile_undelegation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for h in delegation_heights {
|
for h in delegation_heights {
|
||||||
let storage_key = (
|
let delegation =
|
||||||
pending_undelegate.mix_identity(),
|
delegation_map.load(storage, pending_undelegate.delegation_key(h).clone())?;
|
||||||
maybe_proxy_storage.clone(),
|
|
||||||
h,
|
|
||||||
);
|
|
||||||
let delegation = delegation_map.load(storage, storage_key.clone())?;
|
|
||||||
total_delegation += delegation.amount.amount;
|
total_delegation += delegation.amount.amount;
|
||||||
delegation_map.replace(storage, storage_key, None, Some(&delegation))?;
|
delegation_map.replace(
|
||||||
|
storage,
|
||||||
|
pending_undelegate.delegation_key(h),
|
||||||
|
None,
|
||||||
|
Some(&delegation),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bank_msg = BankMsg::Send {
|
let bank_msg = BankMsg::Send {
|
||||||
@@ -386,19 +377,17 @@ pub(crate) fn _try_remove_delegation_from_mixnode(
|
|||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
let delegate = deps.api.addr_validate(delegate)?;
|
let delegate = deps.api.addr_validate(delegate)?;
|
||||||
|
|
||||||
|
let event = PendingUndelegate::new(
|
||||||
|
mix_identity.to_string(),
|
||||||
|
delegate.clone(),
|
||||||
|
proxy.clone(),
|
||||||
|
env.block.height,
|
||||||
|
);
|
||||||
|
|
||||||
PENDING_DELEGATION_EVENTS.save(
|
PENDING_DELEGATION_EVENTS.save(
|
||||||
deps.storage,
|
deps.storage,
|
||||||
(
|
event.event_storage_key(),
|
||||||
delegate.as_bytes().to_vec(),
|
&DelegationEvent::Undelegate(event),
|
||||||
env.block.height,
|
|
||||||
mix_identity.to_string(),
|
|
||||||
),
|
|
||||||
&DelegationEvent::Undelegate(PendingUndelegate::new(
|
|
||||||
mix_identity.to_string(),
|
|
||||||
delegate.clone(),
|
|
||||||
proxy.clone(),
|
|
||||||
env.block.height,
|
|
||||||
)),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Response::new().add_event(new_pending_undelegation_event(
|
Ok(Response::new().add_event(new_pending_undelegation_event(
|
||||||
@@ -738,6 +727,7 @@ mod tests {
|
|||||||
&deps.api,
|
&deps.api,
|
||||||
identity,
|
identity,
|
||||||
delegation_owner.to_string(),
|
delegation_owner.to_string(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -1074,6 +1064,7 @@ mod tests {
|
|||||||
&deps.api,
|
&deps.api,
|
||||||
identity.clone(),
|
identity.clone(),
|
||||||
delegation_owner.clone().into_string(),
|
delegation_owner.clone().into_string(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -1143,6 +1134,7 @@ mod tests {
|
|||||||
&deps.api,
|
&deps.api,
|
||||||
identity.clone(),
|
identity.clone(),
|
||||||
delegation_owner.clone().into_string(),
|
delegation_owner.clone().into_string(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -40,19 +40,6 @@ pub(crate) fn epoch_reward_params(
|
|||||||
Ok(epoch_reward_params)
|
Ok(epoch_reward_params)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_storage_key(address: &Addr, proxy: Option<&Addr>) -> Vec<u8> {
|
|
||||||
if let Some(proxy) = &proxy {
|
|
||||||
address
|
|
||||||
.as_bytes()
|
|
||||||
.iter()
|
|
||||||
.zip(proxy.as_bytes())
|
|
||||||
.map(|(x, y)| x ^ y)
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
address.as_bytes().to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the target address has already bonded a mixnode or gateway,
|
// check if the target address has already bonded a mixnode or gateway,
|
||||||
// in either case, return an appropriate error
|
// in either case, return an appropriate error
|
||||||
pub(crate) fn ensure_no_existing_bond(
|
pub(crate) fn ensure_no_existing_bond(
|
||||||
|
|||||||
@@ -103,12 +103,13 @@ pub mod test_helpers {
|
|||||||
storage: &mut dyn Storage,
|
storage: &mut dyn Storage,
|
||||||
mix: impl Into<String>,
|
mix: impl Into<String>,
|
||||||
owner: impl Into<String>,
|
owner: impl Into<String>,
|
||||||
|
block_height: u64,
|
||||||
) {
|
) {
|
||||||
let delegation = Delegation {
|
let delegation = Delegation {
|
||||||
owner: Addr::unchecked(owner.into()),
|
owner: Addr::unchecked(owner.into()),
|
||||||
node_identity: mix.into(),
|
node_identity: mix.into(),
|
||||||
amount: coin(12345, DENOM),
|
amount: coin(12345, DENOM),
|
||||||
block_height: 12345,
|
block_height: block_height,
|
||||||
proxy: None,
|
proxy: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vesting-contract"
|
name = "vesting-contract"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Drazen Urch <durch@users.noreply.github.com>"]
|
authors = ["Drazen Urch <durch@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-
|
|||||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||||
config = { path = "../../common/config" }
|
config = { path = "../../common/config" }
|
||||||
|
|
||||||
cosmwasm-std = { version = "1.0.0-beta4"}
|
cosmwasm-std = { version = "1.0.0-beta6"}
|
||||||
cw-storage-plus = { version = "0.12.1", features = ["iterator"] }
|
cw-storage-plus = { version = "0.13.1", features = ["iterator"] }
|
||||||
|
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "0.1.0"
|
version = "1.0.0-rc.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nym-gateway"
|
name = "nym-gateway"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Mixnet Gateway"
|
description = "Implementation of the Nym Mixnet Gateway"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nym-mixnode"
|
name = "nym-mixnode"
|
||||||
version = "0.12.1"
|
version = "1.0.0-rc.1"
|
||||||
authors = [
|
authors = [
|
||||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||||
|
|||||||
Generated
-1
@@ -2843,7 +2843,6 @@ dependencies = [
|
|||||||
"argon2",
|
"argon2",
|
||||||
"base64",
|
"base64",
|
||||||
"bip39",
|
"bip39",
|
||||||
"cfg-if",
|
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
"config",
|
"config",
|
||||||
"cosmrs",
|
"cosmrs",
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ tauri-macros = "=1.0.0-rc.1"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bip39 = "1.0"
|
bip39 = "1.0"
|
||||||
cfg-if = "1.0.0"
|
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
eyre = "0.6.5"
|
eyre = "0.6.5"
|
||||||
futures = "0.3.15"
|
futures = "0.3.15"
|
||||||
|
|||||||
@@ -77,18 +77,10 @@ pub enum BackendError {
|
|||||||
NetworkNotSupported(config::defaults::all::Network),
|
NetworkNotSupported(config::defaults::all::Network),
|
||||||
#[error("Could not access the local data storage directory")]
|
#[error("Could not access the local data storage directory")]
|
||||||
UnknownStorageDirectory,
|
UnknownStorageDirectory,
|
||||||
|
#[error("No nymd validator configured")]
|
||||||
|
NoNymdValidatorConfigured,
|
||||||
#[error("No validator API URL configured")]
|
#[error("No validator API URL configured")]
|
||||||
NoValidatorApiUrlConfigured,
|
NoValidatorApiUrlConfigured,
|
||||||
#[error("The wallet file already exists")]
|
|
||||||
WalletFileAlreadyExists,
|
|
||||||
#[error("The wallet file is not found")]
|
|
||||||
WalletFileNotFound,
|
|
||||||
#[error("Account ID not found in wallet")]
|
|
||||||
NoSuchIdInWallet,
|
|
||||||
#[error("Account ID already found in wallet")]
|
|
||||||
IdAlreadyExistsInWallet,
|
|
||||||
#[error("Adding a different password to the wallet not currently supported")]
|
|
||||||
WalletDifferentPasswordDetected,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for BackendError {
|
impl Serialize for BackendError {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ mod error;
|
|||||||
mod menu;
|
mod menu;
|
||||||
mod network;
|
mod network;
|
||||||
mod operations;
|
mod operations;
|
||||||
mod platform_constants;
|
|
||||||
mod state;
|
mod state;
|
||||||
mod utils;
|
mod utils;
|
||||||
// temporarily until it is actually used
|
// temporarily until it is actually used
|
||||||
@@ -38,11 +37,8 @@ fn main() {
|
|||||||
mixnet::account::connect_with_mnemonic,
|
mixnet::account::connect_with_mnemonic,
|
||||||
mixnet::account::create_new_account,
|
mixnet::account::create_new_account,
|
||||||
mixnet::account::create_new_mnemonic,
|
mixnet::account::create_new_mnemonic,
|
||||||
mixnet::account::create_password,
|
|
||||||
mixnet::account::does_password_file_exist,
|
|
||||||
mixnet::account::get_balance,
|
mixnet::account::get_balance,
|
||||||
mixnet::account::logout,
|
mixnet::account::logout,
|
||||||
mixnet::account::sign_in_with_password,
|
|
||||||
mixnet::account::switch_network,
|
mixnet::account::switch_network,
|
||||||
mixnet::account::update_validator_urls,
|
mixnet::account::update_validator_urls,
|
||||||
mixnet::admin::get_contract_settings,
|
mixnet::admin::get_contract_settings,
|
||||||
|
|||||||
@@ -4,11 +4,8 @@ use crate::error::BackendError;
|
|||||||
use crate::network::Network;
|
use crate::network::Network;
|
||||||
use crate::nymd_client;
|
use crate::nymd_client;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID};
|
|
||||||
|
|
||||||
use bip39::{Language, Mnemonic};
|
use bip39::{Language, Mnemonic};
|
||||||
use config::defaults::COSMOS_DERIVATION_PATH;
|
|
||||||
use cosmrs::bip32::DerivationPath;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -230,10 +227,9 @@ async fn choose_validators(
|
|||||||
.next()
|
.next()
|
||||||
// We always have at least one hardcoded default validator
|
// We always have at least one hardcoded default validator
|
||||||
.unwrap();
|
.unwrap();
|
||||||
log::info!(
|
println!(
|
||||||
"Using default for {network}: {}, {}",
|
"Using default for {network}: {}, {}",
|
||||||
default_validator.nymd_url,
|
default_validator.nymd_url, default_validator.api_url,
|
||||||
default_validator.api_url,
|
|
||||||
);
|
);
|
||||||
default_validator
|
default_validator
|
||||||
});
|
});
|
||||||
@@ -309,10 +305,9 @@ async fn try_connect_to_validator(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if is_validator_connection_ok(&client).await {
|
if is_validator_connection_ok(&client).await {
|
||||||
log::info!(
|
println!(
|
||||||
"Connection ok for {network}: {}, {}",
|
"Connection ok for {network}: {}, {}",
|
||||||
validator.nymd_url,
|
validator.nymd_url, validator.api_url
|
||||||
validator.api_url
|
|
||||||
);
|
);
|
||||||
Ok(Some((network, validator.clone())))
|
Ok(Some((network, validator.clone())))
|
||||||
} else {
|
} else {
|
||||||
@@ -327,45 +322,3 @@ async fn is_validator_connection_ok(client: &Client<SigningNymdClient>) -> bool
|
|||||||
Err(_) | Ok(_) => true,
|
Err(_) | Ok(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn does_password_file_exist() -> Result<bool, BackendError> {
|
|
||||||
log::info!("Checking wallet file");
|
|
||||||
let file = wallet_storage::wallet_login_filepath()?;
|
|
||||||
if file.exists() {
|
|
||||||
log::info!("Exists: {}", file.to_string_lossy());
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
log::info!("Does not exist: {}", file.to_string_lossy());
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn create_password(mnemonic: String, password: String) -> Result<(), BackendError> {
|
|
||||||
if does_password_file_exist()? {
|
|
||||||
return Err(BackendError::WalletFileAlreadyExists);
|
|
||||||
}
|
|
||||||
log::info!("Creating password");
|
|
||||||
|
|
||||||
let mnemonic = Mnemonic::from_str(&mnemonic)?;
|
|
||||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
|
||||||
// Currently we only support a single, default, id in the wallet
|
|
||||||
let id = wallet_storage::WalletAccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
|
|
||||||
let password = wallet_storage::UserPassword::new(password);
|
|
||||||
wallet_storage::store_wallet_login_information(mnemonic, hd_path, id, &password)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn sign_in_with_password(
|
|
||||||
password: String,
|
|
||||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
|
||||||
) -> Result<Account, BackendError> {
|
|
||||||
log::info!("Signing in with password");
|
|
||||||
|
|
||||||
// Currently we only support a single, default, id in the wallet
|
|
||||||
let id = wallet_storage::WalletAccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
|
|
||||||
let password = wallet_storage::UserPassword::new(password);
|
|
||||||
let stored_account = wallet_storage::load_existing_wallet_login_information(&id, &password)?;
|
|
||||||
_connect_with_mnemonic(stored_account.mnemonic().clone(), state).await
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Specify filenames and other platform specific constants to respect platform conventions, or at
|
|
||||||
// least, something popular on each respective platform.
|
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(target_os = "linux")] {
|
|
||||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
|
||||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
|
||||||
} else if #[cfg(taret_os = "macos")] {
|
|
||||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
|
||||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
|
||||||
} else if #[cfg(taret_os = "windows")] {
|
|
||||||
pub const STORAGE_DIR_NAME: &str = "NymWallet";
|
|
||||||
pub const WALLET_INFO_FILENAME: &str = "saved_wallet.json";
|
|
||||||
} else {
|
|
||||||
// This case is likely to be a unix-y system
|
|
||||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
|
||||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,96 +8,6 @@ use std::fmt::Formatter;
|
|||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use crate::error::BackendError;
|
|
||||||
|
|
||||||
use super::encryption::EncryptedData;
|
|
||||||
use super::password::WalletAccountId;
|
|
||||||
use super::UserPassword;
|
|
||||||
|
|
||||||
const CURRENT_WALLET_FILE_VERSION: u32 = 1;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub(crate) struct StoredWallet {
|
|
||||||
version: u32,
|
|
||||||
accounts: Vec<EncryptedAccount>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StoredWallet {
|
|
||||||
pub fn version(&self) -> u32 {
|
|
||||||
self.version
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.accounts.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.accounts.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encrypted_account_by_index(&self, index: usize) -> Option<&EncryptedAccount> {
|
|
||||||
self.accounts.get(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encrypted_account(
|
|
||||||
&self,
|
|
||||||
id: &WalletAccountId,
|
|
||||||
) -> Result<&EncryptedData<StoredAccount>, BackendError> {
|
|
||||||
self
|
|
||||||
.accounts
|
|
||||||
.iter()
|
|
||||||
.find(|account| &account.id == id)
|
|
||||||
.map(|account| &account.account)
|
|
||||||
.ok_or(BackendError::NoSuchIdInWallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_encrypted_account(
|
|
||||||
&mut self,
|
|
||||||
new_account: EncryptedAccount,
|
|
||||||
) -> Result<(), BackendError> {
|
|
||||||
if self.encrypted_account(&new_account.id).is_ok() {
|
|
||||||
return Err(BackendError::IdAlreadyExistsInWallet);
|
|
||||||
}
|
|
||||||
self.accounts.push(new_account);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decrypt_account(
|
|
||||||
&self,
|
|
||||||
id: &WalletAccountId,
|
|
||||||
password: &UserPassword,
|
|
||||||
) -> Result<StoredAccount, BackendError> {
|
|
||||||
self.encrypted_account(id)?.decrypt_struct(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decrypt_all(&self, password: &UserPassword) -> Result<Vec<StoredAccount>, BackendError> {
|
|
||||||
self
|
|
||||||
.accounts
|
|
||||||
.iter()
|
|
||||||
.map(|account| account.account.decrypt_struct(password))
|
|
||||||
.collect::<Result<Vec<_>, _>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn password_can_decrypt_all(&self, password: &UserPassword) -> bool {
|
|
||||||
self.decrypt_all(password).is_ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for StoredWallet {
|
|
||||||
fn default() -> Self {
|
|
||||||
StoredWallet {
|
|
||||||
version: CURRENT_WALLET_FILE_VERSION,
|
|
||||||
accounts: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub(crate) struct EncryptedAccount {
|
|
||||||
pub id: WalletAccountId,
|
|
||||||
pub account: EncryptedData<StoredAccount>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// future-proofing
|
// future-proofing
|
||||||
#[derive(Serialize, Deserialize, Debug, Zeroize)]
|
#[derive(Serialize, Deserialize, Debug, Zeroize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
@@ -114,14 +24,6 @@ impl StoredAccount {
|
|||||||
) -> StoredAccount {
|
) -> StoredAccount {
|
||||||
StoredAccount::Mnemonic(MnemonicAccount { mnemonic, hd_path })
|
StoredAccount::Mnemonic(MnemonicAccount { mnemonic, hd_path })
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we add accounts backed by something that is not a mnemonic, this should probably be changed
|
|
||||||
// to return `Option<..>`.
|
|
||||||
pub(crate) fn mnemonic(&self) -> &bip39::Mnemonic {
|
|
||||||
match self {
|
|
||||||
StoredAccount::Mnemonic(account) => account.mnemonic(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@@ -131,6 +33,8 @@ pub(crate) struct MnemonicAccount {
|
|||||||
hd_path: DerivationPath,
|
hd_path: DerivationPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we only ever want to expose those getters in the test code
|
||||||
|
#[cfg(test)]
|
||||||
impl MnemonicAccount {
|
impl MnemonicAccount {
|
||||||
pub(crate) fn mnemonic(&self) -> &bip39::Mnemonic {
|
pub(crate) fn mnemonic(&self) -> &bip39::Mnemonic {
|
||||||
&self.mnemonic
|
&self.mnemonic
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ pub(crate) struct EncryptedData<T> {
|
|||||||
|
|
||||||
impl<T> Drop for EncryptedData<T> {
|
impl<T> Drop for EncryptedData<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.zeroize();
|
self.zeroize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,19 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
pub(crate) use crate::wallet_storage::password::{UserPassword, WalletAccountId};
|
|
||||||
|
|
||||||
use crate::error::BackendError;
|
use crate::error::BackendError;
|
||||||
use crate::operations::mixnet::account::create_new_account;
|
|
||||||
use crate::platform_constants::{STORAGE_DIR_NAME, WALLET_INFO_FILENAME};
|
|
||||||
use crate::wallet_storage::account_data::StoredAccount;
|
use crate::wallet_storage::account_data::StoredAccount;
|
||||||
use crate::wallet_storage::encryption::{encrypt_struct, EncryptedData};
|
use crate::wallet_storage::encryption::{encrypt_struct, EncryptedData};
|
||||||
|
use crate::wallet_storage::password::UserPassword;
|
||||||
use cosmrs::bip32::DerivationPath;
|
use cosmrs::bip32::DerivationPath;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fs::{create_dir_all, OpenOptions};
|
use std::fs::{create_dir_all, OpenOptions};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use self::account_data::{EncryptedAccount, StoredWallet};
|
|
||||||
|
|
||||||
pub(crate) mod account_data;
|
pub(crate) mod account_data;
|
||||||
pub(crate) mod encryption;
|
pub(crate) mod encryption;
|
||||||
|
|
||||||
mod password;
|
mod password;
|
||||||
|
|
||||||
pub(crate) const DEFAULT_WALLET_ACCOUNT_ID: &str = "default";
|
const STORAGE_DIR_NAME: &str = "NymWallet";
|
||||||
|
const WALLET_INFO_FILENAME: &str = "saved_wallet.json";
|
||||||
|
|
||||||
fn get_storage_directory() -> Result<PathBuf, BackendError> {
|
fn get_storage_directory() -> Result<PathBuf, BackendError> {
|
||||||
tauri::api::path::local_data_dir()
|
tauri::api::path::local_data_dir()
|
||||||
@@ -32,76 +25,52 @@ pub(crate) fn wallet_login_filepath() -> Result<PathBuf, BackendError> {
|
|||||||
get_storage_directory().map(|dir| dir.join(WALLET_INFO_FILENAME))
|
get_storage_directory().map(|dir| dir.join(WALLET_INFO_FILENAME))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load_existing_wallet(password: &UserPassword) -> Result<StoredWallet, BackendError> {
|
|
||||||
let store_dir = get_storage_directory()?;
|
|
||||||
let filepath = store_dir.join(WALLET_INFO_FILENAME);
|
|
||||||
load_existing_wallet_at_file(filepath)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_existing_wallet_at_file(filepath: PathBuf) -> Result<StoredWallet, BackendError> {
|
|
||||||
if !filepath.exists() {
|
|
||||||
return Err(BackendError::WalletFileNotFound);
|
|
||||||
}
|
|
||||||
let file = OpenOptions::new().read(true).open(filepath)?;
|
|
||||||
let wallet: StoredWallet = serde_json::from_reader(file)?;
|
|
||||||
Ok(wallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn load_existing_wallet_login_information(
|
pub(crate) fn load_existing_wallet_login_information(
|
||||||
id: &WalletAccountId,
|
|
||||||
password: &UserPassword,
|
password: &UserPassword,
|
||||||
) -> Result<StoredAccount, BackendError> {
|
) -> Result<Vec<StoredAccount>, BackendError> {
|
||||||
let store_dir = get_storage_directory()?;
|
let store_dir = get_storage_directory()?;
|
||||||
let filepath = store_dir.join(WALLET_INFO_FILENAME);
|
let filepath = store_dir.join(WALLET_INFO_FILENAME);
|
||||||
load_existing_wallet_login_information_at_file(filepath, id, password)
|
|
||||||
|
load_existing_wallet_login_information_at_file(filepath, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_existing_wallet_login_information_at_file(
|
fn load_existing_wallet_login_information_at_file(
|
||||||
filepath: PathBuf,
|
filepath: PathBuf,
|
||||||
id: &WalletAccountId,
|
|
||||||
password: &UserPassword,
|
password: &UserPassword,
|
||||||
) -> Result<StoredAccount, BackendError> {
|
) -> Result<Vec<StoredAccount>, BackendError> {
|
||||||
load_existing_wallet_at_file(filepath)?.decrypt_account(id, password)
|
if !filepath.exists() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
let file = OpenOptions::new().read(true).open(filepath)?;
|
||||||
|
let encrypted_data: EncryptedData<Vec<StoredAccount>> = serde_json::from_reader(file)?;
|
||||||
|
encrypted_data.decrypt_struct(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn store_wallet_login_information(
|
pub(crate) fn store_wallet_login_information(
|
||||||
mnemonic: bip39::Mnemonic,
|
mnemonic: bip39::Mnemonic,
|
||||||
hd_path: DerivationPath,
|
hd_path: DerivationPath,
|
||||||
id: WalletAccountId,
|
password: UserPassword,
|
||||||
password: &UserPassword,
|
|
||||||
) -> Result<(), BackendError> {
|
) -> Result<(), BackendError> {
|
||||||
// make sure the entire directory structure exists
|
// make sure the entire directory structure exists
|
||||||
let store_dir = get_storage_directory()?;
|
let store_dir = get_storage_directory()?;
|
||||||
create_dir_all(&store_dir)?;
|
create_dir_all(&store_dir)?;
|
||||||
let filepath = store_dir.join(WALLET_INFO_FILENAME);
|
let filepath = store_dir.join(WALLET_INFO_FILENAME);
|
||||||
|
|
||||||
store_wallet_login_information_at_file(filepath, mnemonic, hd_path, id, password)
|
store_wallet_login_information_at_file(filepath, mnemonic, hd_path, &password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_wallet_login_information_at_file(
|
fn store_wallet_login_information_at_file(
|
||||||
filepath: PathBuf,
|
filepath: PathBuf,
|
||||||
mnemonic: bip39::Mnemonic,
|
mnemonic: bip39::Mnemonic,
|
||||||
hd_path: DerivationPath,
|
hd_path: DerivationPath,
|
||||||
id: WalletAccountId,
|
|
||||||
password: &UserPassword,
|
password: &UserPassword,
|
||||||
) -> Result<(), BackendError> {
|
) -> Result<(), BackendError> {
|
||||||
let mut stored_wallet = match load_existing_wallet_at_file(filepath.clone()) {
|
let mut all_accounts =
|
||||||
Err(BackendError::WalletFileNotFound) => StoredWallet::default(),
|
load_existing_wallet_login_information_at_file(filepath.clone(), password)?;
|
||||||
result => result?,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Confirm that the given password also can unlock the other entries
|
|
||||||
if !stored_wallet.password_can_decrypt_all(password) {
|
|
||||||
return Err(BackendError::WalletDifferentPasswordDetected);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_account = StoredAccount::new_mnemonic_backed_account(mnemonic, hd_path);
|
let new_account = StoredAccount::new_mnemonic_backed_account(mnemonic, hd_path);
|
||||||
let new_encrypted_account = EncryptedAccount {
|
all_accounts.push(new_account);
|
||||||
id,
|
|
||||||
account: encrypt_struct(&new_account, password)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
stored_wallet.add_encrypted_account(new_encrypted_account)?;
|
let encrypted = encrypt_struct(&all_accounts, password)?;
|
||||||
|
|
||||||
let file = OpenOptions::new()
|
let file = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
@@ -109,7 +78,9 @@ fn store_wallet_login_information_at_file(
|
|||||||
.truncate(true)
|
.truncate(true)
|
||||||
.open(filepath)?;
|
.open(filepath)?;
|
||||||
|
|
||||||
Ok(serde_json::to_writer_pretty(file, &stored_wallet)?)
|
serde_json::to_writer_pretty(file, &encrypted)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function should probably exist, but I guess we need to discuss how it should behave in the context of the UX
|
// this function should probably exist, but I guess we need to discuss how it should behave in the context of the UX
|
||||||
@@ -120,11 +91,15 @@ fn store_wallet_login_information_at_file(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::wallet_storage::encryption::encrypt_data;
|
|
||||||
use config::defaults::COSMOS_DERIVATION_PATH;
|
use config::defaults::COSMOS_DERIVATION_PATH;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
fn read_encrypted_blob(file: PathBuf) -> EncryptedData<Vec<StoredAccount>> {
|
||||||
|
let file = OpenOptions::new().read(true).open(&file).unwrap();
|
||||||
|
serde_json::from_reader(file).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
// I'm not 100% sure how to feel about having to touch the file system at all
|
// I'm not 100% sure how to feel about having to touch the file system at all
|
||||||
#[test]
|
#[test]
|
||||||
fn storing_wallet_information() {
|
fn storing_wallet_information() {
|
||||||
@@ -139,36 +114,29 @@ mod tests {
|
|||||||
let password = UserPassword::new("password".to_string());
|
let password = UserPassword::new("password".to_string());
|
||||||
let bad_password = UserPassword::new("bad-password".to_string());
|
let bad_password = UserPassword::new("bad-password".to_string());
|
||||||
|
|
||||||
let id1 = WalletAccountId::new("first".to_string());
|
// nothing was stored on the disk, so regardless of password used, there will be no error, but
|
||||||
let id2 = WalletAccountId::new("second".to_string());
|
// returned list will be empty
|
||||||
|
assert!(
|
||||||
|
load_existing_wallet_login_information_at_file(wallet_file.clone(), &password)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
load_existing_wallet_login_information_at_file(wallet_file.clone(), &bad_password)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty()
|
||||||
|
);
|
||||||
|
|
||||||
// Nothing was stored on the disk
|
// store the first account
|
||||||
assert!(matches!(
|
|
||||||
load_existing_wallet_at_file(wallet_file.clone()),
|
|
||||||
Err(BackendError::WalletFileNotFound),
|
|
||||||
));
|
|
||||||
assert!(matches!(
|
|
||||||
load_existing_wallet_login_information_at_file(wallet_file.clone(), &id1, &password),
|
|
||||||
Err(BackendError::WalletFileNotFound),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Store the first account
|
|
||||||
store_wallet_login_information_at_file(
|
store_wallet_login_information_at_file(
|
||||||
wallet_file.clone(),
|
wallet_file.clone(),
|
||||||
dummy_account1.clone(),
|
dummy_account1.clone(),
|
||||||
cosmos_hd_path.clone(),
|
cosmos_hd_path.clone(),
|
||||||
id1.clone(),
|
|
||||||
&password,
|
&password,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let stored_wallet = load_existing_wallet_at_file(wallet_file.clone()).unwrap();
|
let encrypted_blob = read_encrypted_blob(wallet_file.clone());
|
||||||
assert_eq!(stored_wallet.len(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
stored_wallet.encrypted_account_by_index(0).unwrap().id,
|
|
||||||
WalletAccountId::new("first".to_string())
|
|
||||||
);
|
|
||||||
let encrypted_blob = &stored_wallet.encrypted_account_by_index(0).unwrap().account;
|
|
||||||
|
|
||||||
// some actual ciphertext was saved
|
// some actual ciphertext was saved
|
||||||
assert!(!encrypted_blob.ciphertext().is_empty());
|
assert!(!encrypted_blob.ciphertext().is_empty());
|
||||||
@@ -178,78 +146,53 @@ mod tests {
|
|||||||
let original_salt = encrypted_blob.salt().to_vec();
|
let original_salt = encrypted_blob.salt().to_vec();
|
||||||
|
|
||||||
// trying to load it with wrong password now fails
|
// trying to load it with wrong password now fails
|
||||||
assert!(matches!(
|
assert!(
|
||||||
load_existing_wallet_login_information_at_file(wallet_file.clone(), &id1, &bad_password),
|
load_existing_wallet_login_information_at_file(wallet_file.clone(), &bad_password).is_err()
|
||||||
Err(BackendError::DecryptionError),
|
);
|
||||||
));
|
|
||||||
// and with the wrong id also fails
|
|
||||||
assert!(matches!(
|
|
||||||
load_existing_wallet_login_information_at_file(wallet_file.clone(), &id2, &password),
|
|
||||||
Err(BackendError::NoSuchIdInWallet),
|
|
||||||
));
|
|
||||||
|
|
||||||
// and storing the same id again fails
|
let loaded_accounts =
|
||||||
assert!(matches!(
|
load_existing_wallet_login_information_at_file(wallet_file.clone(), &password).unwrap();
|
||||||
store_wallet_login_information_at_file(
|
println!("{:?}", loaded_accounts);
|
||||||
wallet_file.clone(),
|
assert_eq!(1, loaded_accounts.len());
|
||||||
dummy_account1.clone(),
|
|
||||||
cosmos_hd_path.clone(),
|
|
||||||
id1.clone(),
|
|
||||||
&password,
|
|
||||||
),
|
|
||||||
Err(BackendError::IdAlreadyExistsInWallet),
|
|
||||||
));
|
|
||||||
|
|
||||||
let loaded_account =
|
let StoredAccount::Mnemonic(acc) = &loaded_accounts[0];
|
||||||
load_existing_wallet_login_information_at_file(wallet_file.clone(), &id1, &password).unwrap();
|
|
||||||
|
|
||||||
let StoredAccount::Mnemonic(ref acc) = loaded_account;
|
|
||||||
assert_eq!(&dummy_account1, acc.mnemonic());
|
assert_eq!(&dummy_account1, acc.mnemonic());
|
||||||
assert_eq!(&cosmos_hd_path, acc.hd_path());
|
assert_eq!(&cosmos_hd_path, acc.hd_path());
|
||||||
|
|
||||||
// Can't store extra account if you use different password
|
// can't store extra account if you use different password
|
||||||
assert!(matches!(
|
assert!(store_wallet_login_information_at_file(
|
||||||
store_wallet_login_information_at_file(
|
wallet_file.clone(),
|
||||||
wallet_file.clone(),
|
dummy_account2.clone(),
|
||||||
dummy_account2.clone(),
|
cosmos_hd_path.clone(),
|
||||||
cosmos_hd_path.clone(),
|
&bad_password,
|
||||||
id2.clone(),
|
)
|
||||||
&bad_password
|
.is_err());
|
||||||
),
|
|
||||||
Err(BackendError::WalletDifferentPasswordDetected),
|
|
||||||
));
|
|
||||||
|
|
||||||
// add extra account properly now
|
// add extra account properly now
|
||||||
store_wallet_login_information_at_file(
|
store_wallet_login_information_at_file(
|
||||||
wallet_file.clone(),
|
wallet_file.clone(),
|
||||||
dummy_account2.clone(),
|
dummy_account2.clone(),
|
||||||
different_hd_path.clone(),
|
different_hd_path.clone(),
|
||||||
id2.clone(),
|
|
||||||
&password,
|
&password,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let loaded_accounts = load_existing_wallet_at_file(wallet_file.clone()).unwrap();
|
let encrypted_blob = read_encrypted_blob(wallet_file.clone());
|
||||||
assert_eq!(2, loaded_accounts.len());
|
|
||||||
let encrypted_blob = &loaded_accounts
|
|
||||||
.encrypted_account_by_index(1)
|
|
||||||
.unwrap()
|
|
||||||
.account;
|
|
||||||
|
|
||||||
// fresh IV and salt are used
|
// fresh IV and salt are used
|
||||||
assert_ne!(original_iv, encrypted_blob.iv());
|
assert_ne!(original_iv, encrypted_blob.iv());
|
||||||
assert_ne!(original_salt, encrypted_blob.salt());
|
assert_ne!(original_salt, encrypted_blob.salt());
|
||||||
|
|
||||||
|
let loaded_accounts =
|
||||||
|
load_existing_wallet_login_information_at_file(wallet_file, &password).unwrap();
|
||||||
|
assert_eq!(2, loaded_accounts.len());
|
||||||
|
|
||||||
// first account should be unchanged
|
// first account should be unchanged
|
||||||
let loaded_account =
|
let StoredAccount::Mnemonic(acc1) = &loaded_accounts[0];
|
||||||
load_existing_wallet_login_information_at_file(wallet_file.clone(), &id1, &password).unwrap();
|
|
||||||
let StoredAccount::Mnemonic(ref acc1) = loaded_account;
|
|
||||||
assert_eq!(&dummy_account1, acc1.mnemonic());
|
assert_eq!(&dummy_account1, acc1.mnemonic());
|
||||||
assert_eq!(&cosmos_hd_path, acc1.hd_path());
|
assert_eq!(&cosmos_hd_path, acc1.hd_path());
|
||||||
|
|
||||||
let loaded_account =
|
let StoredAccount::Mnemonic(acc2) = &loaded_accounts[1];
|
||||||
load_existing_wallet_login_information_at_file(wallet_file, &id2, &password).unwrap();
|
|
||||||
let StoredAccount::Mnemonic(ref acc2) = loaded_account;
|
|
||||||
assert_eq!(&dummy_account2, acc2.mnemonic());
|
assert_eq!(&dummy_account2, acc2.mnemonic());
|
||||||
assert_eq!(&different_hd_path, acc2.hd_path());
|
assert_eq!(&different_hd_path, acc2.hd_path());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,8 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub(crate) struct WalletAccountId(String);
|
|
||||||
|
|
||||||
impl WalletAccountId {
|
|
||||||
pub(crate) fn new(id: String) -> WalletAccountId {
|
|
||||||
WalletAccountId(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<str> for WalletAccountId {
|
|
||||||
fn as_ref(&self) -> &str {
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simple wrapper for String that will get zeroized on drop
|
// simple wrapper for String that will get zeroized on drop
|
||||||
#[derive(Zeroize)]
|
#[derive(Zeroize)]
|
||||||
#[zeroize(drop)]
|
#[zeroize(drop)]
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { Alert, Box, Button, CircularProgress } from '@mui/material';
|
import { Alert, Box, Button, CircularProgress } from '@mui/material';
|
||||||
|
import { useSnackbar } from 'notistack';
|
||||||
import { Fee, NymCard } from '../../components';
|
import { Fee, NymCard } from '../../components';
|
||||||
import { useCheckOwnership } from '../../hooks/useCheckOwnership';
|
import { useCheckOwnership } from '../../hooks/useCheckOwnership';
|
||||||
import { ClientContext } from '../../context/main';
|
import { ClientContext } from '../../context/main';
|
||||||
import { unbond } from '../../requests';
|
import { unbond, vestingUnbond } from '../../requests';
|
||||||
import { PageLayout } from '../../layouts';
|
import { PageLayout } from '../../layouts';
|
||||||
|
|
||||||
export const Unbond = () => {
|
export const Unbond = () => {
|
||||||
@@ -11,6 +12,8 @@ export const Unbond = () => {
|
|||||||
const { checkOwnership, ownership } = useCheckOwnership();
|
const { checkOwnership, ownership } = useCheckOwnership();
|
||||||
const { userBalance, getBondDetails } = useContext(ClientContext);
|
const { userBalance, getBondDetails } = useContext(ClientContext);
|
||||||
|
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initialiseForm = async () => {
|
const initialiseForm = async () => {
|
||||||
await checkOwnership();
|
await checkOwnership();
|
||||||
@@ -32,11 +35,20 @@ export const Unbond = () => {
|
|||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await unbond(ownership.nodeType!);
|
try {
|
||||||
await userBalance.fetchBalance();
|
if (ownership.vestingPledge) {
|
||||||
await getBondDetails();
|
await vestingUnbond(ownership.nodeType!);
|
||||||
await checkOwnership();
|
} else {
|
||||||
setIsLoading(false);
|
await unbond(ownership.nodeType!);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
enqueueSnackbar(`Failed to unbond ${ownership.nodeType}}`, { variant: 'error' });
|
||||||
|
} finally {
|
||||||
|
await getBondDetails();
|
||||||
|
await checkOwnership();
|
||||||
|
await userBalance.fetchBalance();
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
color="inherit"
|
color="inherit"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nym-validator-api"
|
name = "nym-validator-api"
|
||||||
version = "0.12.0"
|
version = "1.0.0-rc.1"
|
||||||
authors = [
|
authors = [
|
||||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ const DEFAULT_PER_NODE_TEST_PACKETS: usize = 3;
|
|||||||
|
|
||||||
const DEFAULT_CACHE_INTERVAL: Duration = Duration::from_secs(30);
|
const DEFAULT_CACHE_INTERVAL: Duration = Duration::from_secs(30);
|
||||||
const DEFAULT_MONITOR_THRESHOLD: u8 = 60;
|
const DEFAULT_MONITOR_THRESHOLD: u8 = 60;
|
||||||
const DEFAULT_MIN_RELIABILITY: u8 = 50;
|
const DEFAULT_MIN_MIXNODE_RELIABILITY: u8 = 50;
|
||||||
|
const DEFAULT_MIN_GATEWAY_RELIABILITY: u8 = 20;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@@ -109,8 +110,8 @@ impl Default for Base {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct NetworkMonitor {
|
pub struct NetworkMonitor {
|
||||||
// Mixnodes and gateways with relialability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.
|
// Mixnodes and gateways with relialability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.
|
||||||
min_reliability: u8,
|
min_mixnode_reliability: u8, // defaults to 50
|
||||||
|
min_gateway_reliability: u8, // defaults to 20
|
||||||
/// Specifies whether network monitoring service is enabled in this process.
|
/// Specifies whether network monitoring service is enabled in this process.
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
|
|
||||||
@@ -192,7 +193,8 @@ impl NetworkMonitor {
|
|||||||
impl Default for NetworkMonitor {
|
impl Default for NetworkMonitor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
NetworkMonitor {
|
NetworkMonitor {
|
||||||
min_reliability: DEFAULT_MIN_RELIABILITY,
|
min_mixnode_reliability: DEFAULT_MIN_MIXNODE_RELIABILITY,
|
||||||
|
min_gateway_reliability: DEFAULT_MIN_GATEWAY_RELIABILITY,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
testnet_mode: false,
|
testnet_mode: false,
|
||||||
all_validator_apis: default_api_endpoints(),
|
all_validator_apis: default_api_endpoints(),
|
||||||
@@ -334,6 +336,16 @@ impl Config {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_min_mixnode_reliability(mut self, min_mixnode_reliability: u8) -> Self {
|
||||||
|
self.network_monitor.min_mixnode_reliability = min_mixnode_reliability;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_min_gateway_reliability(mut self, min_gateway_reliability: u8) -> Self {
|
||||||
|
self.network_monitor.min_gateway_reliability = min_gateway_reliability;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub fn with_eth_private_key(mut self, eth_private_key: String) -> Self {
|
pub fn with_eth_private_key(mut self, eth_private_key: String) -> Self {
|
||||||
self.network_monitor.eth_private_key = eth_private_key;
|
self.network_monitor.eth_private_key = eth_private_key;
|
||||||
@@ -423,8 +435,12 @@ impl Config {
|
|||||||
self.network_monitor.minimum_test_routes
|
self.network_monitor.minimum_test_routes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_min_reliability(&self) -> u8 {
|
pub fn get_min_mixnode_reliability(&self) -> u8 {
|
||||||
self.network_monitor.min_reliability
|
self.network_monitor.min_mixnode_reliability
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_min_gateway_reliability(&self) -> u8 {
|
||||||
|
self.network_monitor.min_gateway_reliability
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_route_test_packets(&self) -> usize {
|
pub fn get_route_test_packets(&self) -> usize {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ mixnet_contract_address = '{{ base.mixnet_contract_address }}'
|
|||||||
[network_monitor]
|
[network_monitor]
|
||||||
|
|
||||||
# Mixnodes and gateways with relialability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.
|
# Mixnodes and gateways with relialability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.
|
||||||
min_reliability = {{ network_monitor.min_reliability }}
|
min_mixnode_reliability = {{ network_monitor.min_mixnode_reliability }} # deafults to 50
|
||||||
|
min_gateway_reliability = {{ network_monitor.min_gateway_reliability }} # defaults to 20
|
||||||
|
|
||||||
# Specifies whether network monitoring service is enabled in this process.
|
# Specifies whether network monitoring service is enabled in this process.
|
||||||
enabled = {{ network_monitor.enabled }}
|
enabled = {{ network_monitor.enabled }}
|
||||||
|
|||||||
@@ -131,9 +131,13 @@ impl<C> ValidatorCacheRefresher<C> {
|
|||||||
self.nymd_client.get_gateways(),
|
self.nymd_client.get_gateways(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let rewarded_set_identities = self.nymd_client.get_rewarded_set_identities().await?;
|
let (rewarded_set, active_set) = if let Ok(rewarded_set_identities) =
|
||||||
let (rewarded_set, active_set) =
|
self.nymd_client.get_rewarded_set_identities().await
|
||||||
self.collect_rewarded_and_active_set_details(&mixnodes, rewarded_set_identities);
|
{
|
||||||
|
self.collect_rewarded_and_active_set_details(&mixnodes, rewarded_set_identities)
|
||||||
|
} else {
|
||||||
|
(Vec::new(), Vec::new())
|
||||||
|
};
|
||||||
|
|
||||||
let epoch_rewarding_params = self.nymd_client.get_current_epoch_reward_params().await?;
|
let epoch_rewarding_params = self.nymd_client.get_current_epoch_reward_params().await?;
|
||||||
|
|
||||||
@@ -154,15 +158,19 @@ impl<C> ValidatorCacheRefresher<C> {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Some(notify) = &self.update_rewarded_set_notify {
|
if let Some(notify) = &self.update_rewarded_set_notify {
|
||||||
let update_details = self
|
if let Ok(update_details) = self
|
||||||
.nymd_client
|
.nymd_client
|
||||||
.get_current_rewarded_set_update_details()
|
.get_current_rewarded_set_update_details()
|
||||||
.await?;
|
.await
|
||||||
|
|
||||||
if update_details.last_refreshed_block + (update_details.refresh_rate_blocks as u64)
|
|
||||||
< update_details.current_height
|
|
||||||
{
|
{
|
||||||
// there's only ever a single waiter -> the set updater
|
if update_details.last_refreshed_block + (update_details.refresh_rate_blocks as u64)
|
||||||
|
< update_details.current_height
|
||||||
|
{
|
||||||
|
// there's only ever a single waiter -> the set updater
|
||||||
|
notify.notify_one()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This has the potential to be spammy, we'll find out
|
||||||
notify.notify_one()
|
notify.notify_one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ const ETH_PRIVATE_KEY: &str = "eth_private_key";
|
|||||||
|
|
||||||
const REWARDING_MONITOR_THRESHOLD_ARG: &str = "monitor-threshold";
|
const REWARDING_MONITOR_THRESHOLD_ARG: &str = "monitor-threshold";
|
||||||
|
|
||||||
|
const MIN_MIXNODE_RELIABILITY_ARG: &str = "min_mixnode_reliability";
|
||||||
|
const MIN_GATEWAY_RELIABILITY_ARG: &str = "min_gateway_reliability";
|
||||||
|
|
||||||
fn parse_validators(raw: &str) -> Vec<Url> {
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
raw.split(',')
|
raw.split(',')
|
||||||
.map(|raw_validator| {
|
.map(|raw_validator| {
|
||||||
@@ -276,6 +279,24 @@ fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
|||||||
config = config.with_minimum_interval_monitor_threshold(monitor_threshold)
|
config = config.with_minimum_interval_monitor_threshold(monitor_threshold)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(reliability) = matches
|
||||||
|
.value_of(MIN_MIXNODE_RELIABILITY_ARG)
|
||||||
|
.map(|t| t.parse::<u8>())
|
||||||
|
{
|
||||||
|
config = config.with_min_mixnode_reliability(
|
||||||
|
reliability.expect("Provided reliability is not a u8 number!"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(reliability) = matches
|
||||||
|
.value_of(MIN_GATEWAY_RELIABILITY_ARG)
|
||||||
|
.map(|t| t.parse::<u8>())
|
||||||
|
{
|
||||||
|
config = config.with_min_gateway_reliability(
|
||||||
|
reliability.expect("Provided reliability is not a u8 number!"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
#[cfg(feature = "coconut")]
|
||||||
if let Some(keypair_path) = matches.value_of(KEYPAIR_ARG) {
|
if let Some(keypair_path) = matches.value_of(KEYPAIR_ARG) {
|
||||||
let keypair_bs58 = std::fs::read_to_string(keypair_path)
|
let keypair_bs58 = std::fs::read_to_string(keypair_path)
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ pub(super) struct Monitor {
|
|||||||
/// The minimum number of test routes that need to be constructed (and working) in order for
|
/// The minimum number of test routes that need to be constructed (and working) in order for
|
||||||
/// a monitor test run to be valid.
|
/// a monitor test run to be valid.
|
||||||
minimum_test_routes: usize,
|
minimum_test_routes: usize,
|
||||||
min_reliability: u8,
|
min_mixnode_reliability: u8,
|
||||||
|
min_gateway_reliability: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Monitor {
|
impl Monitor {
|
||||||
@@ -67,7 +68,8 @@ impl Monitor {
|
|||||||
route_test_packets: config.get_route_test_packets(),
|
route_test_packets: config.get_route_test_packets(),
|
||||||
test_routes: config.get_test_routes(),
|
test_routes: config.get_test_routes(),
|
||||||
minimum_test_routes: config.get_minimum_test_routes(),
|
minimum_test_routes: config.get_minimum_test_routes(),
|
||||||
min_reliability: config.get_min_reliability(),
|
min_mixnode_reliability: config.get_min_mixnode_reliability(),
|
||||||
|
min_gateway_reliability: config.get_min_gateway_reliability(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ impl Monitor {
|
|||||||
// uptime calculations
|
// uptime calculations
|
||||||
|
|
||||||
for result in test_summary.mixnode_results.iter() {
|
for result in test_summary.mixnode_results.iter() {
|
||||||
if result.reliability < self.min_reliability {
|
if result.reliability < self.min_mixnode_reliability {
|
||||||
self.packet_preparer
|
self.packet_preparer
|
||||||
.validator_cache()
|
.validator_cache()
|
||||||
.insert_mixnodes_blacklist(result.identity.clone())
|
.insert_mixnodes_blacklist(result.identity.clone())
|
||||||
@@ -92,7 +94,7 @@ impl Monitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for result in test_summary.gateway_results.iter() {
|
for result in test_summary.gateway_results.iter() {
|
||||||
if result.reliability < self.min_reliability {
|
if result.reliability < self.min_gateway_reliability {
|
||||||
self.packet_preparer
|
self.packet_preparer
|
||||||
.validator_cache()
|
.validator_cache()
|
||||||
.insert_gateways_blacklist(result.identity.clone())
|
.insert_gateways_blacklist(result.identity.clone())
|
||||||
|
|||||||
Reference in New Issue
Block a user