Compare commits

..

9 Commits

Author SHA1 Message Date
Mark Sinclair ae0883241e Network Explorer: change prod env to round robin DNS 2021-12-17 13:07:16 +02:00
Mark Sinclair 11baa99c4b Network Explorer improvements:
- fix up API urls after Network Explorer API changes
- set currency denominations in `.env` file
- set API endpoints in `.env` file
2021-12-17 13:07:16 +02:00
Mark Sinclair 8bc23434ab Network Explorer API improvements:
- upgrade `okapi` for swagger generation across multiple resources
- switched `GET mix-node` to `GET mix-nodes`
- added error message when no geolocation env var is set and process continues
2021-12-17 13:07:16 +02:00
Mark Sinclair 8f6daf1e03 Network Explorer: configure URLs with .env file 2021-12-17 13:07:15 +02:00
Bogdan-Ștefan Neacșu 7f63377d22 Update contract addresses 2021-12-17 13:03:28 +02:00
Bogdan-Ștefan Neacșu 46cb3eca38 Do not set proxy only for this time 2021-12-17 13:02:01 +02:00
Bogdan-Ștefan Neacșu 7b22872c6b Short node identity signature check
Fix tests
2021-12-17 13:02:01 +02:00
Bogdan-Ștefan Neacșu 3342cb13c7 Update network defaults 2021-12-17 13:01:59 +02:00
Bogdan-Ștefan Neacșu 3cd5fc3b22 Make develop branch agnostic of the network 2021-12-17 12:48:29 +02:00
493 changed files with 34352 additions and 37100 deletions
+15 -12
View File
@@ -19,27 +19,30 @@ jobs:
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- uses: actions-rs/cargo@v1 # token credentials (non-coconut) don't work for wasm right now
with: # - uses: actions-rs/cargo@v1
command: build # with:
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown # command: build
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut
- uses: actions-rs/cargo@v1 # for some reason this does not seem to work correctly, leave it for later, building is good enough for now
with: # - uses: actions-rs/cargo@v1
command: test # with:
args: --manifest-path clients/webassembly/Cargo.toml # command: test
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: fmt command: fmt
args: --manifest-path clients/webassembly/Cargo.toml -- --check args: --manifest-path clients/webassembly/Cargo.toml -- --check
- uses: actions-rs/cargo@v1 # for some reason this does not seem to work correctly, leave it for later, building is good enough for now
with: # - uses: actions-rs/cargo@v1
command: clippy # with:
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings # command: clippy
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
-3
View File
@@ -1,3 +0,0 @@
unreleased=true
future-release=v0.12.0
since-tag=v0.11.0
-1
View File
@@ -1 +0,0 @@
2.7.5
+879 -228
View File
File diff suppressed because it is too large Load Diff
Generated
+204 -645
View File
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -17,6 +17,7 @@ members = [
"clients/native/websocket-requests", "clients/native/websocket-requests",
"clients/socks5", "clients/socks5",
"clients/tauri-client/src-tauri", "clients/tauri-client/src-tauri",
"clients/webassembly",
"common/client-libs/gateway-client", "common/client-libs/gateway-client",
"common/client-libs/mixnet-client", "common/client-libs/mixnet-client",
"common/client-libs/validator-client", "common/client-libs/validator-client",
@@ -24,10 +25,8 @@ members = [
"common/config", "common/config",
"common/credentials", "common/credentials",
"common/crypto", "common/crypto",
"common/bandwidth-claim-contract", "common/erc20-bridge-contract",
"common/cosmwasm-smart-contracts/contracts-common", "common/mixnet-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/mixnode-common", "common/mixnode-common",
"common/network-defaults", "common/network-defaults",
"common/nonexhaustive-delayqueue", "common/nonexhaustive-delayqueue",
@@ -53,12 +52,12 @@ members = [
"mixnode", "mixnode",
"service-providers/network-requester", "service-providers/network-requester",
"validator-api", "validator-api",
"validator-api/validator-api-requests",
] ]
default-members = [ default-members = [
"clients/native", "clients/native",
"clients/socks5", "clients/socks5",
# "clients/webassembly",
"gateway", "gateway",
"service-providers/network-requester", "service-providers/network-requester",
"mixnode", "mixnode",
@@ -66,4 +65,4 @@ default-members = [
"explorer-api", "explorer-api",
] ]
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly"] exclude = ["explorer", "contracts", "tokenomics-py"]
+9 -23
View File
@@ -1,36 +1,25 @@
all: clippy-all test fmt all: clippy test fmt
happy: clippy-happy test fmt clippy: clippy-main clippy-contracts clippy-wallet
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
test: test-main test-contracts test-wallet test: test-main test-contracts test-wallet
fmt: fmt-main fmt-contracts fmt-wallet fmt: fmt-main fmt-contracts fmt-wallet
clippy-happy-main: clippy-main:
cargo clippy cargo clippy
clippy-happy-contracts: clippy-contracts:
cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown cargo clippy --manifest-path contracts/Cargo.toml
clippy-happy-wallet: clippy-wallet:
cargo clippy --manifest-path nym-wallet/Cargo.toml cargo clippy --manifest-path nym-wallet/Cargo.toml
clippy-all-main:
cargo clippy --all-features -- -D warnings
clippy-all-contracts:
cargo clippy --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
clippy-all-wallet:
cargo clippy --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
test-main: test-main:
cargo test --all-features cargo test
test-contracts: test-contracts:
cargo test --manifest-path contracts/Cargo.toml --all-features cargo test --manifest-path contracts/Cargo.toml
test-wallet: test-wallet:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features cargo test --manifest-path nym-wallet/Cargo.toml
fmt-main: fmt-main:
cargo fmt --all cargo fmt --all
@@ -40,6 +29,3 @@ fmt-contracts:
fmt-wallet: fmt-wallet:
cargo fmt --manifest-path nym-wallet/Cargo.toml --all cargo fmt --manifest-path nym-wallet/Cargo.toml --all
wasm:
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
+6 -7
View File
@@ -21,8 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
### Building ### Building
Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym). Platform build instructions are available on [our docs site](https://nymtech.net/docs/0.11.0/overview/index/).
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
### Developing ### Developing
@@ -41,13 +40,13 @@ Node, node operator and delegator rewards are determined according to the princi
|<img src="https://render.githubusercontent.com/render/math?math=R">|global share of rewards available, starts at 2% of the reward pool. |<img src="https://render.githubusercontent.com/render/math?math=R">|global share of rewards available, starts at 2% of the reward pool.
|<img src="https://render.githubusercontent.com/render/math?math=R_{i}">|node reward for mixnode `i`. |<img src="https://render.githubusercontent.com/render/math?math=R_{i}">|node reward for mixnode `i`.
|<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}">|ratio of total node stake (node bond + all delegations) to the token circulating supply. |<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}">|ratio of total node stake (node bond + all delegations) to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has pledged to their node to the token circulating supply. |<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has plaged to their node to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k`. |<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k` in testnet Milhon.
|<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `reward set` size, and set to 720 in testnet Sandbox. |<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `active set` size, and set to 5000 in testnet Milhon.
|<img src="https://render.githubusercontent.com/render/math?math=\alpha">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker. |<img src="https://render.githubusercontent.com/render/math?math=\alpha">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in. |<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in testnet Milhon.
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch |<img src="https://render.githubusercontent.com/render/math?math=PF_{i}">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 NYMT. |<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 Nym for testnet Milhon.
Node reward for node `i` is determined as: Node reward for node `i` is determined as:
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "client-core" name = "client-core"
version = "0.12.0" version = "0.11.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2018" edition = "2018"
@@ -13,6 +13,7 @@ use nymsphinx::utils::sample_poisson_duration;
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tokio::time; use tokio::time;
@@ -164,8 +165,8 @@ impl LoopCoverTrafficStream<OsRng> {
} }
} }
pub fn start(mut self) -> JoinHandle<()> { pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
self.run().await; self.run().await;
}) })
} }
@@ -79,9 +79,9 @@ impl KeyManager {
))?; ))?;
let gateway_shared_key: SharedKeys = let gateway_shared_key: SharedKeys =
pemstore::load_key(client_pathfinder.gateway_shared_key())?; pemstore::load_key(&client_pathfinder.gateway_shared_key().to_owned())?;
let ack_key: AckKey = pemstore::load_key(client_pathfinder.ack_key())?; let ack_key: AckKey = pemstore::load_key(&client_pathfinder.ack_key().to_owned())?;
// TODO: ack key is never stored so it is generated now. But perhaps it should be stored // TODO: ack key is never stored so it is generated now. But perhaps it should be stored
// after all for consistency sake? // after all for consistency sake?
@@ -6,6 +6,7 @@ use futures::StreamExt;
use gateway_client::GatewayClient; use gateway_client::GatewayClient;
use log::*; use log::*;
use nymsphinx::forwarding::packet::MixPacket; use nymsphinx::forwarding::packet::MixPacket;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>; pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>;
@@ -71,8 +72,8 @@ impl MixTrafficController {
} }
} }
pub fn start(mut self) -> JoinHandle<()> { pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
self.run().await; self.run().await;
}) })
} }
@@ -22,6 +22,7 @@ use nymsphinx::addressing::clients::Recipient;
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
mod acknowledgement_control; mod acknowledgement_control;
@@ -169,8 +170,10 @@ impl RealMessagesController<OsRng> {
self.ack_control = Some(ack_control_fut.await.unwrap()); self.ack_control = Some(ack_control_fut.await.unwrap());
} }
pub fn start(mut self) -> JoinHandle<Self> { // &Handle is only passed for consistency sake with other client modules, but I think
tokio::spawn(async move { // when we get to refactoring, we should apply gateway approach and make it implicit
pub fn start(mut self, handle: &Handle) -> JoinHandle<Self> {
handle.spawn(async move {
self.run().await; self.run().await;
self self
}) })
@@ -15,6 +15,7 @@ use nymsphinx::params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorith
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage}; use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
// Buffer Requests to say "hey, send any reconstructed messages to this channel" // Buffer Requests to say "hey, send any reconstructed messages to this channel"
@@ -290,8 +291,8 @@ impl RequestReceiver {
} }
} }
fn start(mut self) -> JoinHandle<()> { fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
while let Some(request) = self.query_receiver.next().await { while let Some(request) = self.query_receiver.next().await {
match request { match request {
ReceivedBufferMessage::ReceiverAnnounce(sender) => { ReceivedBufferMessage::ReceiverAnnounce(sender) => {
@@ -321,8 +322,8 @@ impl FragmentedMessageReceiver {
mixnet_packet_receiver, mixnet_packet_receiver,
} }
} }
fn start(mut self) -> JoinHandle<()> { fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
while let Some(new_messages) = self.mixnet_packet_receiver.next().await { while let Some(new_messages) = self.mixnet_packet_receiver.next().await {
self.received_buffer.handle_new_received(new_messages).await; self.received_buffer.handle_new_received(new_messages).await;
} }
@@ -354,9 +355,9 @@ impl ReceivedMessagesBufferController {
} }
} }
pub fn start(self) { pub fn start(self, handle: &Handle) {
// TODO: should we do anything with JoinHandle(s) returned by start methods? // TODO: should we do anything with JoinHandle(s) returned by start methods?
self.fragmented_message_receiver.start(); self.fragmented_message_receiver.start(handle);
self.request_receiver.start(); self.request_receiver.start(handle);
} }
} }
@@ -59,7 +59,7 @@ impl ReplyKeyStorage {
) -> Result<(), ReplyKeyStorageError> { ) -> Result<(), ReplyKeyStorageError> {
let digest = encryption_key.compute_digest(); let digest = encryption_key.compute_digest();
let insertion_result = match self.db.insert(digest, encryption_key.to_bytes()) { let insertion_result = match self.db.insert(digest.to_vec(), encryption_key.to_bytes()) {
Err(e) => Err(ReplyKeyStorageError::DbWriteError(e)), Err(e) => Err(ReplyKeyStorageError::DbWriteError(e)),
Ok(existing_key) => { Ok(existing_key) => {
if existing_key.is_some() { if existing_key.is_some() {
@@ -79,7 +79,7 @@ impl ReplyKeyStorage {
&self, &self,
key_digest: EncryptionKeyDigest, key_digest: EncryptionKeyDigest,
) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> { ) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> {
let removal_result = match self.db.remove(key_digest) { let removal_result = match self.db.remove(&key_digest.to_vec()) {
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)), Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
Ok(existing_key) => { Ok(existing_key) => {
Ok(existing_key.map(|existing_key| self.read_encryption_key(existing_key))) Ok(existing_key.map(|existing_key| self.read_encryption_key(existing_key)))
@@ -10,6 +10,7 @@ use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use std::time; use std::time;
use std::time::Duration; use std::time::Duration;
use tokio::runtime::Handle;
use tokio::sync::{RwLock, RwLockReadGuard}; use tokio::sync::{RwLock, RwLockReadGuard};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use topology::{nym_topology_from_bonds, NymTopology}; use topology::{nym_topology_from_bonds, NymTopology};
@@ -303,8 +304,8 @@ impl TopologyRefresher {
self.topology_accessor.is_routable().await self.topology_accessor.is_routable().await
} }
pub fn start(mut self) -> JoinHandle<()> { pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
loop { loop {
tokio::time::sleep(self.refresh_rate).await; tokio::time::sleep(self.refresh_rate).await;
self.refresh().await; self.refresh().await;
-14
View File
@@ -117,10 +117,6 @@ impl<T: NymConfig> Config<T> {
self.client.id = id; self.client.id = id;
} }
pub fn with_testnet_mode(&mut self, testnet_mode: bool) {
self.client.testnet_mode = testnet_mode;
}
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) { pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
self.client.gateway_id = id.into(); self.client.gateway_id = id.into();
} }
@@ -157,10 +153,6 @@ impl<T: NymConfig> Config<T> {
self.client.id.clone() self.client.id.clone()
} }
pub fn get_testnet_mode(&self) -> bool {
self.client.testnet_mode
}
pub fn get_nym_root_directory(&self) -> PathBuf { pub fn get_nym_root_directory(&self) -> PathBuf {
self.client.nym_root_directory.clone() self.client.nym_root_directory.clone()
} }
@@ -281,11 +273,6 @@ pub struct Client<T> {
/// ID specifies the human readable ID of this particular client. /// ID specifies the human readable ID of this particular client.
id: String, id: String,
/// Indicates whether this client is running in a testnet mode, thus attempting
/// to claim bandwidth without presenting bandwidth credentials.
#[serde(default)]
testnet_mode: bool,
/// Addresses to APIs running on validator from which the client gets the view of the network. /// Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls: Vec<Url>, validator_api_urls: Vec<Url>,
@@ -348,7 +335,6 @@ impl<T: NymConfig> Default for Client<T> {
Client { Client {
version: env!("CARGO_PKG_VERSION").to_string(), version: env!("CARGO_PKG_VERSION").to_string(),
id: "".to_string(), id: "".to_string(),
testnet_mode: false,
validator_api_urls: default_api_endpoints(), validator_api_urls: default_api_endpoints(),
private_identity_key_file: Default::default(), private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(), public_identity_key_file: Default::default(),
+1 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "0.12.1" version = "0.11.0"
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 = "2018" edition = "2018"
rust-version = "1.56" rust-version = "1.56"
@@ -48,7 +48,6 @@ network-defaults = { path = "../../common/network-defaults" }
[features] [features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"] coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" # for the "textsend" example serde_json = "1.0" # for the "textsend" example
@@ -35,7 +35,7 @@ async fn send_file_with_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let read_data = std::fs::read("examples/dummy_file").unwrap(); let read_data = std::fs::read("examples/dummy_file").unwrap();
@@ -83,7 +83,7 @@ async fn send_file_without_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let read_data = std::fs::read("examples/dummy_file").unwrap(); let read_data = std::fs::read("examples/dummy_file").unwrap();
@@ -36,7 +36,7 @@ async fn send_text_with_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let send_request = json!({ let send_request = json!({
"type" : "send", "type" : "send",
@@ -76,7 +76,7 @@ async fn send_text_without_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let send_request = json!({ let send_request = json!({
"type" : "send", "type" : "send",
+1 -5
View File
@@ -5,7 +5,7 @@ pub(crate) fn config_template() -> &'static str {
// While using normal toml marshalling would have been way simpler with less overhead, // While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of // I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields. // particular fields.
// Note: any changes to the template must be reflected in the appropriate structs. // Note: any changes to the template must be reflected in the appropriate structs in verloc.
r#" r#"
# This is a TOML config file. # This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml # For more information, see https://github.com/toml-lang/toml
@@ -19,10 +19,6 @@ version = '{{ client.version }}'
# Human readable ID of this particular client. # Human readable ID of this particular client.
id = '{{ client.id }}' id = '{{ client.id }}'
# Indicates whether this client is running in a testnet mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
testnet_mode = {{ client.testnet_mode }}
# Addresses to APIs running on validator from which the client gets the view of the network. # Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls = [ validator_api_urls = [
{{#each client.validator_api_urls }} {{#each client.validator_api_urls }}
+63 -49
View File
@@ -32,6 +32,7 @@ use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity; use nymsphinx::addressing::nodes::NodeIdentity;
use nymsphinx::anonymous_replies::ReplySurb; use nymsphinx::anonymous_replies::ReplySurb;
use nymsphinx::receiver::ReconstructedMessage; use nymsphinx::receiver::ReconstructedMessage;
use tokio::runtime::Runtime;
use crate::client::config::{Config, SocketType}; use crate::client::config::{Config, SocketType};
use crate::websocket; use crate::websocket;
@@ -43,6 +44,11 @@ pub struct NymClient {
/// key filepaths, etc. /// key filepaths, etc.
config: Config, config: Config,
/// Tokio runtime used for futures execution.
// TODO: JS: Personally I think I prefer the implicit way of using it that we've done with the
// gateway.
runtime: Runtime,
/// KeyManager object containing smart pointers to all relevant keys used by the client. /// KeyManager object containing smart pointers to all relevant keys used by the client.
key_manager: KeyManager, key_manager: KeyManager,
@@ -62,6 +68,7 @@ impl NymClient {
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys"); let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
NymClient { NymClient {
runtime: Runtime::new().unwrap(),
config, config,
key_manager, key_manager,
input_tx: None, input_tx: None,
@@ -87,6 +94,9 @@ impl NymClient {
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor which HAS TO be called within context of a tokio runtime
let _guard = self.runtime.enter();
LoopCoverTrafficStream::new( LoopCoverTrafficStream::new(
self.key_manager.ack_key(), self.key_manager.ack_key(),
@@ -99,7 +109,7 @@ impl NymClient {
self.as_mix_recipient(), self.as_mix_recipient(),
topology_accessor, topology_accessor,
) )
.start(); .start(self.runtime.handle());
} }
fn start_real_traffic_controller( fn start_real_traffic_controller(
@@ -121,6 +131,10 @@ impl NymClient {
); );
info!("Starting real traffic stream..."); info!("Starting real traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
// When refactoring this restriction should definitely be removed.
let _guard = self.runtime.enter();
RealMessagesController::new( RealMessagesController::new(
controller_config, controller_config,
@@ -130,7 +144,7 @@ impl NymClient {
topology_accessor, topology_accessor,
reply_key_storage, reply_key_storage,
) )
.start(); .start(self.runtime.handle());
} }
// buffer controlling all messages fetched from provider // buffer controlling all messages fetched from provider
@@ -148,10 +162,10 @@ impl NymClient {
mixnet_receiver, mixnet_receiver,
reply_key_storage, reply_key_storage,
) )
.start() .start(self.runtime.handle())
} }
async fn start_gateway_client( fn start_gateway_client(
&mut self, &mut self,
mixnet_message_sender: MixnetMessageSender, mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender, ack_sender: AcknowledgementSender,
@@ -168,44 +182,43 @@ impl NymClient {
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.expect("provided gateway id is invalid!"); .expect("provided gateway id is invalid!");
#[cfg(feature = "coconut")] self.runtime.block_on(async {
let bandwidth_controller = BandwidthController::new( #[cfg(feature = "coconut")]
self.config.get_base().get_validator_api_endpoints(), let bandwidth_controller = BandwidthController::new(
*self.key_manager.identity_keypair().public_key(), self.config.get_base().get_validator_api_endpoints(),
); *self.key_manager.identity_keypair().public_key(),
#[cfg(not(feature = "coconut"))] );
let bandwidth_controller = BandwidthController::new( #[cfg(not(feature = "coconut"))]
self.config.get_base().get_eth_endpoint(), let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_eth_private_key(), self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_backup_bandwidth_token_keys_dir(), self.config.get_base().get_eth_private_key(),
) self.config.get_base().get_backup_bandwidth_token_keys_dir(),
.expect("Could not create bandwidth controller"); )
.expect("Could not create bandwidth controller");
let mut gateway_client = GatewayClient::new( let mut gateway_client = GatewayClient::new(
gateway_address, gateway_address,
self.key_manager.identity_keypair(), self.key_manager.identity_keypair(),
gateway_identity, gateway_identity,
Some(self.key_manager.gateway_shared_key()), Some(self.key_manager.gateway_shared_key()),
mixnet_message_sender, mixnet_message_sender,
ack_sender, ack_sender,
self.config.get_base().get_gateway_response_timeout(), self.config.get_base().get_gateway_response_timeout(),
Some(bandwidth_controller), Some(bandwidth_controller),
); );
if self.config.get_base().get_testnet_mode() { gateway_client
gateway_client.set_testnet_mode(true) .authenticate_and_start()
} .await
gateway_client .expect("could not authenticate and start up the gateway connection");
.authenticate_and_start()
.await
.expect("could not authenticate and start up the gateway connection");
gateway_client gateway_client
})
} }
// future responsible for periodically polling directory server and updating // future responsible for periodically polling directory server and updating
// the current global view of topology // the current global view of topology
async fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) { fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
let topology_refresher_config = TopologyRefresherConfig::new( let topology_refresher_config = TopologyRefresherConfig::new(
self.config.get_base().get_validator_api_endpoints(), self.config.get_base().get_validator_api_endpoints(),
self.config.get_base().get_topology_refresh_rate(), self.config.get_base().get_topology_refresh_rate(),
@@ -216,10 +229,13 @@ impl NymClient {
// before returning, block entire runtime to refresh the current network view so that any // before returning, block entire runtime to refresh the current network view so that any
// components depending on topology would see a non-empty view // components depending on topology would see a non-empty view
info!("Obtaining initial network topology"); info!("Obtaining initial network topology");
topology_refresher.refresh().await; self.runtime.block_on(topology_refresher.refresh());
// TODO: a slightly more graceful termination here // TODO: a slightly more graceful termination here
if !topology_refresher.is_topology_routable().await { if !self
.runtime
.block_on(topology_refresher.is_topology_routable())
{
panic!( panic!(
"The current network topology seem to be insufficient to route any packets through\ "The current network topology seem to be insufficient to route any packets through\
- check if enough nodes and a gateway are online" - check if enough nodes and a gateway are online"
@@ -227,7 +243,7 @@ impl NymClient {
} }
info!("Starting topology refresher..."); info!("Starting topology refresher...");
topology_refresher.start(); topology_refresher.start(self.runtime.handle());
} }
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic) // controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
@@ -240,7 +256,7 @@ impl NymClient {
gateway_client: GatewayClient, gateway_client: GatewayClient,
) { ) {
info!("Starting mix traffic controller..."); info!("Starting mix traffic controller...");
MixTrafficController::new(mix_rx, gateway_client).start(); MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle());
} }
fn start_websocket_listener( fn start_websocket_listener(
@@ -253,7 +269,8 @@ impl NymClient {
let websocket_handler = let websocket_handler =
websocket::Handler::new(msg_input, buffer_requester, self.as_mix_recipient()); websocket::Handler::new(msg_input, buffer_requester, self.as_mix_recipient());
websocket::Listener::new(self.config.get_listening_port()).start(websocket_handler); websocket::Listener::new(self.config.get_listening_port())
.start(self.runtime.handle(), websocket_handler);
} }
/// EXPERIMENTAL DIRECT RUST API /// EXPERIMENTAL DIRECT RUST API
@@ -300,9 +317,9 @@ impl NymClient {
} }
/// blocking version of `start` method. Will run forever (or until SIGINT is sent) /// blocking version of `start` method. Will run forever (or until SIGINT is sent)
pub async fn run_forever(&mut self) { pub fn run_forever(&mut self) {
self.start().await; self.start();
if let Err(e) = tokio::signal::ctrl_c().await { if let Err(e) = self.runtime.block_on(tokio::signal::ctrl_c()) {
error!( error!(
"There was an error while capturing SIGINT - {:?}. We will terminate regardless", "There was an error while capturing SIGINT - {:?}. We will terminate regardless",
e e
@@ -314,7 +331,7 @@ impl NymClient {
); );
} }
pub async fn start(&mut self) { pub fn start(&mut self) {
info!("Starting nym client"); info!("Starting nym client");
// channels for inter-component communication // channels for inter-component communication
// TODO: make the channels be internally created by the relevant components // TODO: make the channels be internally created by the relevant components
@@ -346,17 +363,14 @@ impl NymClient {
// the components are started in very specific order. Unless you know what you are doing, // the components are started in very specific order. Unless you know what you are doing,
// do not change that. // do not change that.
self.start_topology_refresher(shared_topology_accessor.clone()) self.start_topology_refresher(shared_topology_accessor.clone());
.await;
self.start_received_messages_buffer_controller( self.start_received_messages_buffer_controller(
received_buffer_request_receiver, received_buffer_request_receiver,
mixnet_messages_receiver, mixnet_messages_receiver,
reply_key_storage.clone(), reply_key_storage.clone(),
); );
let gateway_client = self let gateway_client = self.start_gateway_client(mixnet_messages_sender, ack_sender);
.start_gateway_client(mixnet_messages_sender, ack_sender)
.await;
self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client); self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client);
self.start_real_traffic_controller( self.start_real_traffic_controller(
+26 -36
View File
@@ -31,12 +31,6 @@ use url::Url;
use crate::client::config::Config; use crate::client::config::Config;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
TESTNET_MODE_ARG_NAME,
};
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
let app = App::new("init") let app = App::new("init")
@@ -72,28 +66,18 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.hidden(true) // this will prevent this flag from being displayed in `--help` .hidden(true) // this will prevent this flag from being displayed in `--help`
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init") .help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
); );
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
let app = app let app = app
.arg( .arg(Arg::with_name("eth_endpoint")
Arg::with_name(TESTNET_MODE_ARG_NAME) .long("eth_endpoint")
.long(TESTNET_MODE_ARG_NAME) .help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
)
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true) .takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
.required(true)) .required(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME) .arg(Arg::with_name("eth_private_key")
.long(ETH_PRIVATE_KEY_ARG_NAME) .long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead") .help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true) .takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY) .required(true));
.required(true)
);
app app
} }
@@ -219,7 +203,7 @@ fn show_address(config: &Config) {
println!("\nThe address of this client is: {}", client_recipient); println!("\nThe address of this client is: {}", client_recipient);
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
println!("Initialising client..."); println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now let id = matches.value_of("id").unwrap(); // required for now
@@ -237,7 +221,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
// TODO: ideally that should be the last thing that's being done to config. // TODO: ideally that should be the last thing that's being done to config.
// However, we are later further overriding it with gateway id // However, we are later further overriding it with gateway id
config = override_config(config, &matches); config = override_config(config, matches);
if matches.is_present("fastmode") { if matches.is_present("fastmode") {
config.get_base_mut().set_high_default_traffic_volume(); config.get_base_mut().set_high_default_traffic_volume();
} }
@@ -250,20 +234,26 @@ pub async fn execute(matches: ArgMatches<'static>) {
let chosen_gateway_id = matches.value_of("gateway"); let chosen_gateway_id = matches.value_of("gateway");
let gateway_details = gateway_details( let registration_fut = async {
config.get_base().get_validator_api_endpoints(), let gate_details = gateway_details(
chosen_gateway_id, config.get_base().get_validator_api_endpoints(),
) chosen_gateway_id,
.await; )
config .await;
.get_base_mut() config
.with_gateway_id(gateway_details.identity_key.to_base58_string()); .get_base_mut()
let shared_keys = .with_gateway_id(gate_details.identity_key.to_base58_string());
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let rt = tokio::runtime::Runtime::new().unwrap();
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
config config
.get_base_mut() .get_base_mut()
.with_gateway_listener(gateway_details.clients_address()); .with_gateway_listener(gateway_listener);
key_manager.insert_gateway_shared_key(shared_keys); key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
+2 -26
View File
@@ -5,18 +5,6 @@ use crate::client::config::{Config, SocketType};
use clap::ArgMatches; use clap::ArgMatches;
use url::Url; use url::Url;
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
pub(crate) mod init; pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
pub(crate) mod upgrade; pub(crate) mod upgrade;
@@ -56,24 +44,12 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
} }
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) { if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
config.get_base_mut().with_eth_endpoint(eth_endpoint); config.get_base_mut().with_eth_endpoint(eth_endpoint);
} else {
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
} }
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) { if let Some(eth_private_key) = matches.value_of("eth_private_key") {
config.get_base_mut().with_eth_private_key(eth_private_key); config.get_base_mut().with_eth_private_key(eth_private_key);
} else {
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
}
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
config.get_base_mut().with_testnet_mode(true)
} }
config config
+9 -19
View File
@@ -4,9 +4,6 @@
use crate::client::config::Config; use crate::client::config::Config;
use crate::client::NymClient; use crate::client::NymClient;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use config::NymConfig; use config::NymConfig;
use log::*; use log::*;
@@ -42,22 +39,15 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.help("Port for the socket (if applicable) to listen on") .help("Port for the socket (if applicable) to listen on")
.takes_value(true) .takes_value(true)
); );
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
let app = app let app = app
.arg( .arg(Arg::with_name("eth_endpoint")
Arg::with_name(TESTNET_MODE_ARG_NAME) .long("eth_endpoint")
.long(TESTNET_MODE_ARG_NAME) .help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
)
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true)) .takes_value(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME) .arg(Arg::with_name("eth_private_key")
.long(ETH_PRIVATE_KEY_ARG_NAME) .long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead") .help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true)); .takes_value(true));
app app
@@ -82,7 +72,7 @@ fn version_check(cfg: &Config) -> bool {
} }
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
let id = matches.value_of("id").unwrap(); let id = matches.value_of("id").unwrap();
let mut config = match Config::load_from_file(Some(id)) { let mut config = match Config::load_from_file(Some(id)) {
@@ -93,12 +83,12 @@ pub async fn execute(matches: ArgMatches<'static>) {
} }
}; };
config = override_config(config, &matches); config = override_config(config, matches);
if !version_check(&config) { if !version_check(&config) {
error!("failed the local version check"); error!("failed the local version check");
return; return;
} }
NymClient::new(config).run_forever().await; NymClient::new(config).run_forever();
} }
+5 -6
View File
@@ -7,8 +7,7 @@ pub mod client;
pub mod commands; pub mod commands;
pub mod websocket; pub mod websocket;
#[tokio::main] fn main() {
async fn main() {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
setup_logging(); setup_logging();
println!("{}", banner()); println!("{}", banner());
@@ -23,13 +22,13 @@ async fn main() {
.subcommand(commands::upgrade::command_args()) .subcommand(commands::upgrade::command_args())
.get_matches(); .get_matches();
execute(arg_matches).await; execute(arg_matches);
} }
async fn execute(matches: ArgMatches<'static>) { fn execute(matches: ArgMatches) {
match matches.subcommand() { match matches.subcommand() {
("init", Some(m)) => commands::init::execute(m.clone()).await, ("init", Some(m)) => commands::init::execute(m),
("run", Some(m)) => commands::run::execute(m.clone()).await, ("run", Some(m)) => commands::run::execute(m),
("upgrade", Some(m)) => commands::upgrade::execute(m), ("upgrade", Some(m)) => commands::upgrade::execute(m),
_ => println!("{}", usage()), _ => println!("{}", usage()),
} }
+3 -2
View File
@@ -5,6 +5,7 @@ use super::handler::Handler;
use log::*; use log::*;
use std::{net::SocketAddr, process, sync::Arc}; use std::{net::SocketAddr, process, sync::Arc};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::runtime;
use tokio::{sync::Notify, task::JoinHandle}; use tokio::{sync::Notify, task::JoinHandle};
enum State { enum State {
@@ -86,9 +87,9 @@ impl Listener {
} }
} }
pub(crate) fn start(mut self, handler: Handler) -> JoinHandle<()> { pub(crate) fn start(mut self, rt_handle: &runtime::Handle, handler: Handler) -> JoinHandle<()> {
info!("Running websocket on {:?}", self.address.to_string()); info!("Running websocket on {:?}", self.address.to_string());
tokio::spawn(async move { self.run(handler).await }) rt_handle.spawn(async move { self.run(handler).await })
} }
} }
+1 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "0.12.1" version = "0.11.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2018" edition = "2018"
rust-version = "1.56" rust-version = "1.56"
@@ -43,7 +43,6 @@ network-defaults = { path = "../../common/network-defaults" }
[features] [features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"] coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[build-dependencies] [build-dependencies]
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
+1 -5
View File
@@ -5,7 +5,7 @@ pub(crate) fn config_template() -> &'static str {
// While using normal toml marshalling would have been way simpler with less overhead, // While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of // I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields. // particular fields.
// Note: any changes to the template must be reflected in the appropriate structs. // Note: any changes to the template must be reflected in the appropriate structs in verloc.
r#" r#"
# This is a TOML config file. # This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml # For more information, see https://github.com/toml-lang/toml
@@ -19,10 +19,6 @@ version = '{{ client.version }}'
# Human readable ID of this particular client. # Human readable ID of this particular client.
id = '{{ client.id }}' id = '{{ client.id }}'
# Indicates whether this client is running in a testnet mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
testnet_mode = {{ client.testnet_mode }}
# Addresses to APIs running on validator from which the client gets the view of the network. # Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls = [ validator_api_urls = [
{{#each client.validator_api_urls }} {{#each client.validator_api_urls }}
+63 -49
View File
@@ -28,6 +28,7 @@ use gateway_client::{
use log::*; use log::*;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity; use nymsphinx::addressing::nodes::NodeIdentity;
use tokio::runtime::Runtime;
use crate::client::config::Config; use crate::client::config::Config;
use crate::socks::{ use crate::socks::{
@@ -42,6 +43,11 @@ pub struct NymClient {
/// key filepaths, etc. /// key filepaths, etc.
config: Config, config: Config,
/// Tokio runtime used for futures execution.
// TODO: JS: Personally I think I prefer the implicit way of using it that we've done with the
// gateway.
runtime: Runtime,
/// KeyManager object containing smart pointers to all relevant keys used by the client. /// KeyManager object containing smart pointers to all relevant keys used by the client.
key_manager: KeyManager, key_manager: KeyManager,
} }
@@ -52,6 +58,7 @@ impl NymClient {
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys"); let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
NymClient { NymClient {
runtime: Runtime::new().unwrap(),
config, config,
key_manager, key_manager,
} }
@@ -75,6 +82,9 @@ impl NymClient {
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor which HAS TO be called within context of a tokio runtime
let _guard = self.runtime.enter();
LoopCoverTrafficStream::new( LoopCoverTrafficStream::new(
self.key_manager.ack_key(), self.key_manager.ack_key(),
@@ -87,7 +97,7 @@ impl NymClient {
self.as_mix_recipient(), self.as_mix_recipient(),
topology_accessor, topology_accessor,
) )
.start(); .start(self.runtime.handle());
} }
fn start_real_traffic_controller( fn start_real_traffic_controller(
@@ -109,6 +119,10 @@ impl NymClient {
); );
info!("Starting real traffic stream..."); info!("Starting real traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
// When refactoring this restriction should definitely be removed.
let _guard = self.runtime.enter();
RealMessagesController::new( RealMessagesController::new(
controller_config, controller_config,
@@ -118,7 +132,7 @@ impl NymClient {
topology_accessor, topology_accessor,
reply_key_storage, reply_key_storage,
) )
.start(); .start(self.runtime.handle());
} }
// buffer controlling all messages fetched from provider // buffer controlling all messages fetched from provider
@@ -136,10 +150,10 @@ impl NymClient {
mixnet_receiver, mixnet_receiver,
reply_key_storage, reply_key_storage,
) )
.start() .start(self.runtime.handle())
} }
async fn start_gateway_client( fn start_gateway_client(
&mut self, &mut self,
mixnet_message_sender: MixnetMessageSender, mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender, ack_sender: AcknowledgementSender,
@@ -156,44 +170,43 @@ impl NymClient {
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.expect("provided gateway id is invalid!"); .expect("provided gateway id is invalid!");
#[cfg(feature = "coconut")] self.runtime.block_on(async {
let bandwidth_controller = BandwidthController::new( #[cfg(feature = "coconut")]
self.config.get_base().get_validator_api_endpoints(), let bandwidth_controller = BandwidthController::new(
*self.key_manager.identity_keypair().public_key(), self.config.get_base().get_validator_api_endpoints(),
); *self.key_manager.identity_keypair().public_key(),
#[cfg(not(feature = "coconut"))] );
let bandwidth_controller = BandwidthController::new( #[cfg(not(feature = "coconut"))]
self.config.get_base().get_eth_endpoint(), let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_eth_private_key(), self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_backup_bandwidth_token_keys_dir(), self.config.get_base().get_eth_private_key(),
) self.config.get_base().get_backup_bandwidth_token_keys_dir(),
.expect("Could not create bandwidth controller"); )
.expect("Could not create bandwidth controller");
let mut gateway_client = GatewayClient::new( let mut gateway_client = GatewayClient::new(
gateway_address, gateway_address,
self.key_manager.identity_keypair(), self.key_manager.identity_keypair(),
gateway_identity, gateway_identity,
Some(self.key_manager.gateway_shared_key()), Some(self.key_manager.gateway_shared_key()),
mixnet_message_sender, mixnet_message_sender,
ack_sender, ack_sender,
self.config.get_base().get_gateway_response_timeout(), self.config.get_base().get_gateway_response_timeout(),
Some(bandwidth_controller), Some(bandwidth_controller),
); );
if self.config.get_base().get_testnet_mode() { gateway_client
gateway_client.set_testnet_mode(true) .authenticate_and_start()
} .await
gateway_client .expect("could not authenticate and start up the gateway connection");
.authenticate_and_start()
.await
.expect("could not authenticate and start up the gateway connection");
gateway_client gateway_client
})
} }
// future responsible for periodically polling directory server and updating // future responsible for periodically polling directory server and updating
// the current global view of topology // the current global view of topology
async fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) { fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
let topology_refresher_config = TopologyRefresherConfig::new( let topology_refresher_config = TopologyRefresherConfig::new(
self.config.get_base().get_validator_api_endpoints(), self.config.get_base().get_validator_api_endpoints(),
self.config.get_base().get_topology_refresh_rate(), self.config.get_base().get_topology_refresh_rate(),
@@ -204,10 +217,13 @@ impl NymClient {
// before returning, block entire runtime to refresh the current network view so that any // before returning, block entire runtime to refresh the current network view so that any
// components depending on topology would see a non-empty view // components depending on topology would see a non-empty view
info!("Obtaining initial network topology"); info!("Obtaining initial network topology");
topology_refresher.refresh().await; self.runtime.block_on(topology_refresher.refresh());
// TODO: a slightly more graceful termination here // TODO: a slightly more graceful termination here
if !topology_refresher.is_topology_routable().await { if !self
.runtime
.block_on(topology_refresher.is_topology_routable())
{
panic!( panic!(
"The current network topology seem to be insufficient to route any packets through\ "The current network topology seem to be insufficient to route any packets through\
- check if enough nodes and a gateway are online" - check if enough nodes and a gateway are online"
@@ -215,7 +231,7 @@ impl NymClient {
} }
info!("Starting topology refresher..."); info!("Starting topology refresher...");
topology_refresher.start(); topology_refresher.start(self.runtime.handle());
} }
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic) // controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
@@ -228,7 +244,7 @@ impl NymClient {
gateway_client: GatewayClient, gateway_client: GatewayClient,
) { ) {
info!("Starting mix traffic controller..."); info!("Starting mix traffic controller...");
MixTrafficController::new(mix_rx, gateway_client).start(); MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle());
} }
fn start_socks5_listener( fn start_socks5_listener(
@@ -247,13 +263,14 @@ impl NymClient {
self.config.get_provider_mix_address(), self.config.get_provider_mix_address(),
self.as_mix_recipient(), self.as_mix_recipient(),
); );
tokio::spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await }); self.runtime
.spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await });
} }
/// blocking version of `start` method. Will run forever (or until SIGINT is sent) /// blocking version of `start` method. Will run forever (or until SIGINT is sent)
pub async fn run_forever(&mut self) { pub fn run_forever(&mut self) {
self.start().await; self.start();
if let Err(e) = tokio::signal::ctrl_c().await { if let Err(e) = self.runtime.block_on(tokio::signal::ctrl_c()) {
error!( error!(
"There was an error while capturing SIGINT - {:?}. We will terminate regardless", "There was an error while capturing SIGINT - {:?}. We will terminate regardless",
e e
@@ -265,7 +282,7 @@ impl NymClient {
); );
} }
pub async fn start(&mut self) { pub fn start(&mut self) {
info!("Starting nym client"); info!("Starting nym client");
// channels for inter-component communication // channels for inter-component communication
// TODO: make the channels be internally created by the relevant components // TODO: make the channels be internally created by the relevant components
@@ -297,17 +314,14 @@ impl NymClient {
// the components are started in very specific order. Unless you know what you are doing, // the components are started in very specific order. Unless you know what you are doing,
// do not change that. // do not change that.
self.start_topology_refresher(shared_topology_accessor.clone()) self.start_topology_refresher(shared_topology_accessor.clone());
.await;
self.start_received_messages_buffer_controller( self.start_received_messages_buffer_controller(
received_buffer_request_receiver, received_buffer_request_receiver,
mixnet_messages_receiver, mixnet_messages_receiver,
reply_key_storage.clone(), reply_key_storage.clone(),
); );
let gateway_client = self let gateway_client = self.start_gateway_client(mixnet_messages_sender, ack_sender);
.start_gateway_client(mixnet_messages_sender, ack_sender)
.await;
self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client); self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client);
self.start_real_traffic_controller( self.start_real_traffic_controller(
+26 -36
View File
@@ -29,12 +29,6 @@ use url::Url;
use crate::client::config::Config; use crate::client::config::Config;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
TESTNET_MODE_ARG_NAME,
};
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
let app = App::new("init") let app = App::new("init")
@@ -72,28 +66,18 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.hidden(true) // this will prevent this flag from being displayed in `--help` .hidden(true) // this will prevent this flag from being displayed in `--help`
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init") .help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
); );
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
let app = app let app = app
.arg( .arg(Arg::with_name("eth_endpoint")
Arg::with_name(TESTNET_MODE_ARG_NAME) .long("eth_endpoint")
.long(TESTNET_MODE_ARG_NAME) .help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
)
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true) .takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
.required(true)) .required(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME) .arg(Arg::with_name("eth_private_key")
.long(ETH_PRIVATE_KEY_ARG_NAME) .long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead") .help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true) .takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY) .required(true));
.required(true)
);
app app
} }
@@ -219,7 +203,7 @@ fn show_address(config: &Config) {
println!("\nThe address of this client is: {}", client_recipient); println!("\nThe address of this client is: {}", client_recipient);
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
println!("Initialising client..."); println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now let id = matches.value_of("id").unwrap(); // required for now
@@ -238,7 +222,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
// TODO: ideally that should be the last thing that's being done to config. // TODO: ideally that should be the last thing that's being done to config.
// However, we are later further overriding it with gateway id // However, we are later further overriding it with gateway id
config = override_config(config, &matches); config = override_config(config, matches);
if matches.is_present("fastmode") { if matches.is_present("fastmode") {
config.get_base_mut().set_high_default_traffic_volume(); config.get_base_mut().set_high_default_traffic_volume();
} }
@@ -251,20 +235,26 @@ pub async fn execute(matches: ArgMatches<'static>) {
let chosen_gateway_id = matches.value_of("gateway"); let chosen_gateway_id = matches.value_of("gateway");
let gateway_details = gateway_details( let registration_fut = async {
config.get_base().get_validator_api_endpoints(), let gate_details = gateway_details(
chosen_gateway_id, config.get_base().get_validator_api_endpoints(),
) chosen_gateway_id,
.await; )
config .await;
.get_base_mut() config
.with_gateway_id(gateway_details.identity_key.to_base58_string()); .get_base_mut()
let shared_keys = .with_gateway_id(gate_details.identity_key.to_base58_string());
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
let rt = tokio::runtime::Runtime::new().unwrap();
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
config config
.get_base_mut() .get_base_mut()
.with_gateway_listener(gateway_details.clients_address()); .with_gateway_listener(gateway_listener);
key_manager.insert_gateway_shared_key(shared_keys); key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
+2 -26
View File
@@ -9,18 +9,6 @@ pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
pub(crate) mod upgrade; pub(crate) mod upgrade;
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
fn parse_validators(raw: &str) -> Vec<Url> { fn parse_validators(raw: &str) -> Vec<Url> {
raw.split(',') raw.split(',')
.map(|raw_validator| { .map(|raw_validator| {
@@ -52,24 +40,12 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
} }
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) { if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
config.get_base_mut().with_eth_endpoint(eth_endpoint); config.get_base_mut().with_eth_endpoint(eth_endpoint);
} else {
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
} }
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) { if let Some(eth_private_key) = matches.value_of("eth_private_key") {
config.get_base_mut().with_eth_private_key(eth_private_key); config.get_base_mut().with_eth_private_key(eth_private_key);
} else {
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
}
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
config.get_base_mut().with_testnet_mode(true)
} }
config config
+9 -19
View File
@@ -4,9 +4,6 @@
use crate::client::config::Config; use crate::client::config::Config;
use crate::client::NymClient; use crate::client::NymClient;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use config::NymConfig; use config::NymConfig;
use log::*; use log::*;
@@ -48,22 +45,15 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.help("Port for the socket to listen on") .help("Port for the socket to listen on")
.takes_value(true) .takes_value(true)
); );
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))] #[cfg(not(feature = "coconut"))]
let app = app let app = app
.arg( .arg(Arg::with_name("eth_endpoint")
Arg::with_name(TESTNET_MODE_ARG_NAME) .long("eth_endpoint")
.long(TESTNET_MODE_ARG_NAME) .help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
)
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true)) .takes_value(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME) .arg(Arg::with_name("eth_private_key")
.long(ETH_PRIVATE_KEY_ARG_NAME) .long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead") .help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true)); .takes_value(true));
app app
@@ -88,7 +78,7 @@ fn version_check(cfg: &Config) -> bool {
} }
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
let id = matches.value_of("id").unwrap(); let id = matches.value_of("id").unwrap();
let mut config = match Config::load_from_file(Some(id)) { let mut config = match Config::load_from_file(Some(id)) {
@@ -99,12 +89,12 @@ pub async fn execute(matches: ArgMatches<'static>) {
} }
}; };
config = override_config(config, &matches); config = override_config(config, matches);
if !version_check(&config) { if !version_check(&config) {
error!("failed the local version check"); error!("failed the local version check");
return; return;
} }
NymClient::new(config).run_forever().await; NymClient::new(config).run_forever();
} }
+5 -6
View File
@@ -7,8 +7,7 @@ pub mod client;
mod commands; mod commands;
pub mod socks; pub mod socks;
#[tokio::main] fn main() {
async fn main() {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
setup_logging(); setup_logging();
println!("{}", banner()); println!("{}", banner());
@@ -23,13 +22,13 @@ async fn main() {
.subcommand(commands::upgrade::command_args()) .subcommand(commands::upgrade::command_args())
.get_matches(); .get_matches();
execute(arg_matches).await; execute(arg_matches);
} }
async fn execute(matches: ArgMatches<'static>) { fn execute(matches: ArgMatches) {
match matches.subcommand() { match matches.subcommand() {
("init", Some(m)) => commands::init::execute(m.clone()).await, ("init", Some(m)) => commands::init::execute(m),
("run", Some(m)) => commands::run::execute(m.clone()).await, ("run", Some(m)) => commands::run::execute(m),
("upgrade", Some(m)) => commands::upgrade::execute(m), ("upgrade", Some(m)) => commands::upgrade::execute(m),
_ => println!("{}", usage()), _ => println!("{}", usage()),
} }
+3 -11
View File
@@ -180,8 +180,8 @@ export default class ValidatorClient implements INymClient {
return this.client.getSybilResistancePercent(this.mixnetContract); return this.client.getSybilResistancePercent(this.mixnetContract);
} }
public async getIntervalRewardPercent(): Promise<number> { public async getEpochRewardPercent(): Promise<number> {
return this.client.getIntervalRewardPercent(this.mixnetContract); return this.client.getEpochRewardPercent(this.mixnetContract);
} }
public async getAllNymdMixnodes(): Promise<MixNodeBond[]> { public async getAllNymdMixnodes(): Promise<MixNodeBond[]> {
@@ -433,14 +433,6 @@ export default class ValidatorClient implements INymClient {
return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixIdentity, fee, memo); return (this.client as ISigningClient).undelegateFromMixNode(this.mixnetContract, mixIdentity, fee, memo);
} }
public async updateMixnodeConfig(
mixIdentity: string,
fee: StdFee | 'auto' | number,
profitPercentage: number,
): Promise<ExecuteResult> {
return (this.client as ISigningClient).updateMixnodeConfig(this.mixnetContract, mixIdentity, profitPercentage, fee);
}
public async updateContractStateParams( public async updateContractStateParams(
newParams: ContractStateParams, newParams: ContractStateParams,
fee?: StdFee | 'auto' | number, fee?: StdFee | 'auto' | number,
@@ -449,4 +441,4 @@ export default class ValidatorClient implements INymClient {
this.assertSigning(); this.assertSigning();
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo); return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
} }
} }
+9 -2
View File
@@ -18,6 +18,7 @@ import {
PagedGatewayResponse, PagedGatewayResponse,
PagedMixDelegationsResponse, PagedMixDelegationsResponse,
PagedMixnodeResponse, PagedMixnodeResponse,
RewardingIntervalResponse,
RewardingStatus, RewardingStatus,
} from './types'; } from './types';
@@ -78,6 +79,12 @@ export default class NymdQuerier implements INymdQuery {
}); });
} }
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
return this.client.queryContractSmart(mixnetContractAddress, {
current_rewarding_interval: {},
});
}
getAllNetworkDelegationsPaged( getAllNetworkDelegationsPaged(
mixnetContractAddress: string, mixnetContractAddress: string,
limit?: number, limit?: number,
@@ -148,9 +155,9 @@ export default class NymdQuerier implements INymdQuery {
}); });
} }
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> { getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
return this.client.queryContractSmart(mixnetContractAddress, { return this.client.queryContractSmart(mixnetContractAddress, {
get_interval_reward_percent: {}, get_epoch_reward_percent: {},
}); });
} }
+9 -3
View File
@@ -28,6 +28,7 @@ import {
PagedGatewayResponse, PagedGatewayResponse,
PagedMixDelegationsResponse, PagedMixDelegationsResponse,
PagedMixnodeResponse, PagedMixnodeResponse,
RewardingIntervalResponse,
RewardingStatus, RewardingStatus,
} from './types'; } from './types';
import ValidatorApiQuerier, { IValidatorApiQuery } from './validator-api-querier'; import ValidatorApiQuerier, { IValidatorApiQuery } from './validator-api-querier';
@@ -62,6 +63,7 @@ export interface INymdQuery {
ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>; ownsMixNode(mixnetContractAddress: string, address: string): Promise<MixOwnershipResponse>;
ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse>; ownsGateway(mixnetContractAddress: string, address: string): Promise<GatewayOwnershipResponse>;
getStateParams(mixnetContractAddress: string): Promise<ContractStateParams>; getStateParams(mixnetContractAddress: string): Promise<ContractStateParams>;
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse>;
getAllNetworkDelegationsPaged( getAllNetworkDelegationsPaged(
mixnetContractAddress: string, mixnetContractAddress: string,
@@ -85,7 +87,7 @@ export interface INymdQuery {
getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>; getLayerDistribution(mixnetContractAddress: string): Promise<LayerDistribution>;
getRewardPool(mixnetContractAddress: string): Promise<string>; getRewardPool(mixnetContractAddress: string): Promise<string>;
getCirculatingSupply(mixnetContractAddress: string): Promise<string>; getCirculatingSupply(mixnetContractAddress: string): Promise<string>;
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number>; getEpochRewardPercent(mixnetContractAddress: string): Promise<number>;
getSybilResistancePercent(mixnetContractAddress: string): Promise<number>; getSybilResistancePercent(mixnetContractAddress: string): Promise<number>;
getRewardingStatus( getRewardingStatus(
mixnetContractAddress: string, mixnetContractAddress: string,
@@ -136,6 +138,10 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
return this.nymdQuerier.getStateParams(mixnetContractAddress); return this.nymdQuerier.getStateParams(mixnetContractAddress);
} }
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
return this.nymdQuerier.getCurrentRewardingInterval(mixnetContractAddress);
}
getAllNetworkDelegationsPaged( getAllNetworkDelegationsPaged(
mixnetContractAddress: string, mixnetContractAddress: string,
limit?: number, limit?: number,
@@ -178,8 +184,8 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress); return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress);
} }
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> { getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
return this.nymdQuerier.getIntervalRewardPercent(mixnetContractAddress); return this.nymdQuerier.getEpochRewardPercent(mixnetContractAddress);
} }
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> { getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
+7 -23
View File
@@ -31,6 +31,7 @@ import {
PagedGatewayResponse, PagedGatewayResponse,
PagedMixDelegationsResponse, PagedMixDelegationsResponse,
PagedMixnodeResponse, PagedMixnodeResponse,
RewardingIntervalResponse,
RewardingStatus, RewardingStatus,
} from './types'; } from './types';
import ValidatorApiQuerier from './validator-api-querier'; import ValidatorApiQuerier from './validator-api-querier';
@@ -177,13 +178,6 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
memo?: string, memo?: string,
): Promise<ExecuteResult>; ): Promise<ExecuteResult>;
updateMixnodeConfig(
mixnetContractAddress: string,
mixIdentity: string,
profitMarginPercent: number,
fee: StdFee | 'auto' | number,
): Promise<ExecuteResult>;
updateContractStateParams( updateContractStateParams(
mixnetContractAddress: string, mixnetContractAddress: string,
newParams: ContractStateParams, newParams: ContractStateParams,
@@ -256,6 +250,10 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
return this.nymdQuerier.getStateParams(mixnetContractAddress); return this.nymdQuerier.getStateParams(mixnetContractAddress);
} }
getCurrentRewardingInterval(mixnetContractAddress: string): Promise<RewardingIntervalResponse> {
return this.nymdQuerier.getCurrentRewardingInterval(mixnetContractAddress);
}
getAllNetworkDelegationsPaged( getAllNetworkDelegationsPaged(
mixnetContractAddress: string, mixnetContractAddress: string,
limit?: number, limit?: number,
@@ -298,8 +296,8 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress); return this.nymdQuerier.getCirculatingSupply(mixnetContractAddress);
} }
getIntervalRewardPercent(mixnetContractAddress: string): Promise<number> { getEpochRewardPercent(mixnetContractAddress: string): Promise<number> {
return this.nymdQuerier.getIntervalRewardPercent(mixnetContractAddress); return this.nymdQuerier.getEpochRewardPercent(mixnetContractAddress);
} }
getSybilResistancePercent(mixnetContractAddress: string): Promise<number> { getSybilResistancePercent(mixnetContractAddress: string): Promise<number> {
@@ -450,20 +448,6 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
); );
} }
updateMixnodeConfig(
mixnetContractAddress: string,
mixIdentity: string,
profitMarginPercent: number,
fee: StdFee | 'auto' | number,
): Promise<ExecuteResult> {
return this.execute(
this.clientAddress,
mixnetContractAddress,
{ update_mixnode_config: { profit_margin_percent: profitMarginPercent, mix_identity: mixIdentity } },
fee,
);
}
updateContractStateParams( updateContractStateParams(
mixnetContractAddress: string, mixnetContractAddress: string,
newParams: ContractStateParams, newParams: ContractStateParams,
+6 -1
View File
@@ -43,6 +43,12 @@ export type ContractStateParams = {
mixnode_active_set_size: number; mixnode_active_set_size: number;
}; };
export type RewardingIntervalResponse = {
current_rewarding_interval_starting_block: number;
current_rewarding_interval_nonce: number;
rewarding_in_progress: boolean;
};
export type LayerDistribution = { export type LayerDistribution = {
gateways: number; gateways: number;
layer1: number; layer1: number;
@@ -129,7 +135,6 @@ export type MixNode = {
sphinx_key: string; sphinx_key: string;
identity_key: string; identity_key: string;
version: string; version: string;
profit_margin_percent: number;
}; };
export type GatewayBond = { export type GatewayBond = {
+2 -2
View File
@@ -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 = "0.11.0"
edition = "2018" edition = "2018"
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"] keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
license = "Apache-2.0" license = "Apache-2.0"
@@ -32,7 +32,7 @@ credentials = { path = "../../common/credentials", optional = true }
crypto = { path = "../../common/crypto" } crypto = { path = "../../common/crypto" }
nymsphinx = { path = "../../common/nymsphinx" } nymsphinx = { path = "../../common/nymsphinx" }
topology = { path = "../../common/topology" } topology = { path = "../../common/topology" }
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] } gateway-client = { path = "../../common/client-libs/gateway-client" }
validator-client = { path = "../../common/client-libs/validator-client", default-features = false } validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
wasm-utils = { path = "../../common/wasm-utils" } wasm-utils = { path = "../../common/wasm-utils" }
+2 -14
View File
@@ -3,6 +3,7 @@
use crypto::asymmetric::{encryption, identity}; use crypto::asymmetric::{encryption, identity};
use futures::channel::mpsc; use futures::channel::mpsc;
use gateway_client::bandwidth::BandwidthController;
use gateway_client::GatewayClient; use gateway_client::GatewayClient;
use nymsphinx::acknowledgements::AckKey; use nymsphinx::acknowledgements::AckKey;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
@@ -26,7 +27,6 @@ const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
#[wasm_bindgen] #[wasm_bindgen]
pub struct NymClient { pub struct NymClient {
validator_server: Url, validator_server: Url,
testnet_mode: bool,
// TODO: technically this doesn't need to be an Arc since wasm is run on a single thread // TODO: technically this doesn't need to be an Arc since wasm is run on a single thread
// however, once we eventually combine this code with the native-client's, it will make things // however, once we eventually combine this code with the native-client's, it will make things
@@ -72,7 +72,6 @@ impl NymClient {
on_message: None, on_message: None,
on_gateway_connect: None, on_gateway_connect: None,
testnet_mode: false,
} }
} }
@@ -85,11 +84,6 @@ impl NymClient {
self.on_gateway_connect = Some(on_connect) self.on_gateway_connect = Some(on_connect)
} }
pub fn set_testnet_mode(&mut self, testnet_mode: bool) {
console_log!("Setting testnet mode to {}", testnet_mode);
self.testnet_mode = testnet_mode;
}
fn self_recipient(&self) -> Recipient { fn self_recipient(&self) -> Recipient {
Recipient::new( Recipient::new(
*self.identity.public_key(), *self.identity.public_key(),
@@ -107,10 +101,8 @@ impl NymClient {
// Right now it's impossible to have async exported functions to take `&self` rather than self // Right now it's impossible to have async exported functions to take `&self` rather than self
pub async fn initial_setup(self) -> Self { pub async fn initial_setup(self) -> Self {
let testnet_mode = self.testnet_mode;
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
let bandwidth_controller = Some(gateway_client::bandwidth::BandwidthController::new( let bandwidth_controller = Some(BandwidthController::new(
vec![self.validator_server.clone()], vec![self.validator_server.clone()],
*self.identity.public_key(), *self.identity.public_key(),
)); ));
@@ -134,10 +126,6 @@ impl NymClient {
bandwidth_controller, bandwidth_controller,
); );
if testnet_mode {
gateway_client.set_testnet_mode(true)
}
gateway_client gateway_client
.authenticate_and_start() .authenticate_and_start()
.await .await
+7 -5
View File
@@ -15,8 +15,6 @@ log = "0.4"
thiserror = "1.0" thiserror = "1.0"
url = "2.2" url = "2.2"
rand = { version = "0.7.3", features = ["wasm-bindgen"] } rand = { version = "0.7.3", features = ["wasm-bindgen"] }
secp256k1 = "0.20.3"
web3 = { version = "0.17.0", default-features = false }
# internal # internal
credentials = { path = "../../credentials" } credentials = { path = "../../credentials" }
@@ -38,6 +36,12 @@ features = ["macros", "rt", "net", "sync", "time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
version = "0.14" version = "0.14"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.secp256k1]
version = "0.20.3"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.web3]
version = "0.17.0"
# wasm-only dependencies # wasm-only dependencies
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen] [target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
version = "0.2" version = "0.2"
@@ -66,6 +70,4 @@ features = ["js"]
#url = "2.1" #url = "2.1"
[features] [features]
coconut = ["gateway-requests/coconut", "coconut-interface"] coconut = ["gateway-requests/coconut", "coconut-interface"]
wasm = ["web3/wasm", "web3/http", "web3/signing"]
default = ["web3/default"]
@@ -203,7 +203,7 @@ impl BandwidthController {
&self.eth_private_key, &self.eth_private_key,
) )
.await?; .await?;
if Some(U64::from(0u64)) == recipt.status { if Some(U64::from(0)) == recipt.status {
Err(GatewayClientError::BurnTokenError( Err(GatewayClientError::BurnTokenError(
web3::Error::InvalidResponse(format!( web3::Error::InvalidResponse(format!(
"Transaction status is 0 (failure): {:?}", "Transaction status is 0 (failure): {:?}",
@@ -40,7 +40,6 @@ const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
pub struct GatewayClient { pub struct GatewayClient {
authenticated: bool, authenticated: bool,
testnet_mode: bool,
bandwidth_remaining: i64, bandwidth_remaining: i64,
gateway_address: String, gateway_address: String,
gateway_identity: identity::PublicKey, gateway_identity: identity::PublicKey,
@@ -76,7 +75,6 @@ impl GatewayClient {
) -> Self { ) -> Self {
GatewayClient { GatewayClient {
authenticated: false, authenticated: false,
testnet_mode: false,
bandwidth_remaining: 0, bandwidth_remaining: 0,
gateway_address, gateway_address,
gateway_identity, gateway_identity,
@@ -92,10 +90,6 @@ impl GatewayClient {
} }
} }
pub fn set_testnet_mode(&mut self, testnet_mode: bool) {
self.testnet_mode = testnet_mode
}
// TODO: later convert into proper builder methods // TODO: later convert into proper builder methods
pub fn with_reconnection_on_failure(&mut self, should_reconnect_on_failure: bool) { pub fn with_reconnection_on_failure(&mut self, should_reconnect_on_failure: bool) {
self.should_reconnect_on_failure = should_reconnect_on_failure self.should_reconnect_on_failure = should_reconnect_on_failure
@@ -125,7 +119,6 @@ impl GatewayClient {
GatewayClient { GatewayClient {
authenticated: false, authenticated: false,
testnet_mode: false,
bandwidth_remaining: 0, bandwidth_remaining: 0,
gateway_address, gateway_address,
gateway_identity, gateway_identity,
@@ -520,17 +513,6 @@ impl GatewayClient {
Ok(()) Ok(())
} }
async fn try_claim_testnet_bandwidth(&mut self) -> Result<(), GatewayClientError> {
let msg = ClientControlRequest::ClaimFreeTestnetBandwidth.into();
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { available_total } => Ok(available_total),
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
_ => Err(GatewayClientError::UnexpectedResponse),
}?;
Ok(())
}
pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError> { pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError> {
if !self.authenticated { if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated); return Err(GatewayClientError::NotAuthenticated);
@@ -543,10 +525,6 @@ impl GatewayClient {
} }
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while"); warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
if self.testnet_mode {
info!("The client is running in testnet mode - attempting to claim bandwidth without a credential");
return self.try_claim_testnet_bandwidth().await;
}
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
let credential = self let credential = self
+9 -24
View File
@@ -9,18 +9,17 @@ rust-version = "1.56"
[dependencies] [dependencies]
base64 = "0.13" base64 = "0.13"
mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract" } mixnet-contract = { path="../../../common/mixnet-contract" }
vesting-contract = { path = "../../../contracts/vesting" } vesting-contract = { path="../../../contracts/vesting" }
serde = { version = "1", features = ["derive"] } serde = { version="1", features=["derive"] }
serde_json = "1" serde_json = "1"
reqwest = { version = "0.11", features = ["json"] } reqwest = { version="0.11", features=["json"] }
thiserror = "1" thiserror = "1"
log = "0.4" log = "0.4"
url = { version = "2.2", features = ["serde"] } 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" }
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
# required for nymd-client # required for nymd-client
# at some point it might be possible to make it wasm-compatible # at some point it might be possible to make it wasm-compatible
@@ -28,28 +27,14 @@ validator-api-requests = { path = "../../../validator-api/validator-api-requests
async-trait = { version = "0.1.51", optional = true } async-trait = { version = "0.1.51", optional = true }
bip39 = { version = "1", features = ["rand"], optional = true } bip39 = { version = "1", features = ["rand"], optional = true }
config = { path = "../../config", optional = true } config = { path = "../../config", optional = true }
cosmrs = { version = "0.4.1", features = [ #cosmrs = { version = "0.3", features = ["rpc", "bip32", "cosmwasm"], optional = true }
"rpc", cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev="e5a1872083abb3d88fa62dda966e7f5408deba58", features = ["rpc", "bip32", "cosmwasm"], optional = true }
"bip32",
"cosmwasm",
], optional = true }
prost = { version = "0.9", default-features = false, optional = true } 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-beta2", optional = true }
ts-rs = { version = "5.1", optional = true } ts-rs = {version = "5.1", optional = true}
[features] [features]
nymd-client = [ nymd-client = ["async-trait", "bip39", "config", "cosmrs", "prost", "flate2", "sha2", "itertools", "cosmwasm-std"]
"async-trait",
"bip39",
"config",
"cosmrs",
"prost",
"flate2",
"sha2",
"itertools",
"cosmwasm-std",
]
typescript-types = ["ts-rs", "validator-api-requests/ts-rs"]
+24 -230
View File
@@ -6,30 +6,21 @@ use crate::nymd::{
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient, error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
}; };
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
use mixnet_contract_common::ContractStateParams; use mixnet_contract::ContractStateParams;
use crate::{validator_api, ValidatorClientError}; use crate::{validator_api, ValidatorClientError};
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse}; use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
use mixnet_contract_common::{ use mixnet_contract::{
Delegation, Interval, MixnetContractVersion, MixnodeRewardingStatusResponse, Delegation, MixnetContractVersion, MixnodeRewardingStatusResponse, RewardingIntervalResponse,
};
use mixnet_contract_common::{
GatewayBond, IdentityKey, IdentityKeyRef, MixNodeBond, RewardedSetNodeStatus,
RewardedSetUpdateDetails,
}; };
use mixnet_contract::{GatewayBond, MixNodeBond};
use std::collections::{HashMap, HashSet};
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
use std::str::FromStr; use std::str::FromStr;
use url::Url; use url::Url;
use validator_api_requests::models::{
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
StakeSaturationResponse,
};
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
#[must_use]
pub struct Config { pub struct Config {
api_url: Url, api_url: Url,
nymd_url: Url, nymd_url: Url,
@@ -39,7 +30,6 @@ pub struct Config {
mixnode_page_limit: Option<u32>, mixnode_page_limit: Option<u32>,
gateway_page_limit: Option<u32>, gateway_page_limit: Option<u32>,
mixnode_delegations_page_limit: Option<u32>, mixnode_delegations_page_limit: Option<u32>,
rewarded_set_page_limit: Option<u32>,
} }
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
@@ -58,7 +48,6 @@ impl Config {
mixnode_page_limit: None, mixnode_page_limit: None,
gateway_page_limit: None, gateway_page_limit: None,
mixnode_delegations_page_limit: None, mixnode_delegations_page_limit: None,
rewarded_set_page_limit: None,
} }
} }
@@ -76,11 +65,6 @@ impl Config {
self.mixnode_delegations_page_limit = limit; self.mixnode_delegations_page_limit = limit;
self self
} }
pub fn with_rewarded_set_page_limit(mut self, limit: Option<u32>) -> Config {
self.rewarded_set_page_limit = limit;
self
}
} }
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
@@ -92,7 +76,6 @@ pub struct Client<C> {
mixnode_page_limit: Option<u32>, mixnode_page_limit: Option<u32>,
gateway_page_limit: Option<u32>, gateway_page_limit: Option<u32>,
mixnode_delegations_page_limit: Option<u32>, mixnode_delegations_page_limit: Option<u32>,
rewarded_set_page_limit: Option<u32>,
// ideally they would have been read-only, but unfortunately rust doesn't have such features // ideally they would have been read-only, but unfortunately rust doesn't have such features
pub validator_api: validator_api::Client, pub validator_api: validator_api::Client,
@@ -121,7 +104,6 @@ impl Client<SigningNymdClient> {
mixnode_page_limit: config.mixnode_page_limit, mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit, gateway_page_limit: config.gateway_page_limit,
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit, mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
rewarded_set_page_limit: None,
validator_api: validator_api_client, validator_api: validator_api_client,
nymd: nymd_client, nymd: nymd_client,
}) })
@@ -145,14 +127,14 @@ impl Client<QueryNymdClient> {
let validator_api_client = validator_api::Client::new(config.api_url.clone()); let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nymd_client = NymdClient::connect( let nymd_client = NymdClient::connect(
config.nymd_url.as_str(), config.nymd_url.as_str(),
Some(config.mixnet_contract_address.clone().unwrap_or_else(|| { config.mixnet_contract_address.clone().unwrap_or_else(|| {
cosmrs::AccountId::from_str(network_defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS) cosmrs::AccountId::from_str(network_defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS)
.unwrap() .unwrap()
})), }),
Some(config.vesting_contract_address.clone().unwrap_or_else(|| { config.vesting_contract_address.clone().unwrap_or_else(|| {
cosmrs::AccountId::from_str(network_defaults::DEFAULT_VESTING_CONTRACT_ADDRESS) cosmrs::AccountId::from_str(network_defaults::DEFAULT_VESTING_CONTRACT_ADDRESS)
.unwrap() .unwrap()
})), }),
)?; )?;
Ok(Client { Ok(Client {
@@ -162,7 +144,6 @@ impl Client<QueryNymdClient> {
mixnode_page_limit: config.mixnode_page_limit, mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit, gateway_page_limit: config.gateway_page_limit,
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit, mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
rewarded_set_page_limit: config.rewarded_set_page_limit,
validator_api: validator_api_client, validator_api: validator_api_client,
nymd: nymd_client, nymd: nymd_client,
}) })
@@ -171,8 +152,8 @@ impl Client<QueryNymdClient> {
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> { pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
self.nymd = NymdClient::connect( self.nymd = NymdClient::connect(
new_endpoint.as_ref(), new_endpoint.as_ref(),
self.mixnet_contract_address.clone(), self.mixnet_contract_address.clone().unwrap(),
self.vesting_contract_address.clone(), self.vesting_contract_address.clone().unwrap(),
)?; )?;
Ok(()) Ok(())
} }
@@ -198,18 +179,6 @@ impl<C> Client<C> {
Ok(self.validator_api.get_mixnodes().await?) Ok(self.validator_api.get_mixnodes().await?)
} }
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes().await?)
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_active_mixnodes().await?)
}
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> { pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.validator_api.get_gateways().await?) Ok(self.validator_api.get_gateways().await?)
} }
@@ -228,9 +197,18 @@ impl<C> Client<C> {
Ok(self.nymd.get_mixnet_contract_version().await?) Ok(self.nymd.get_mixnet_contract_version().await?)
} }
pub async fn get_current_rewarding_interval(
&self,
) -> Result<RewardingIntervalResponse, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_current_rewarding_interval().await?)
}
pub async fn get_rewarding_status( pub async fn get_rewarding_status(
&self, &self,
mix_identity: mixnet_contract_common::IdentityKey, mix_identity: mixnet_contract::IdentityKey,
rewarding_interval_nonce: u32, rewarding_interval_nonce: u32,
) -> Result<MixnodeRewardingStatusResponse, ValidatorClientError> ) -> Result<MixnodeRewardingStatusResponse, ValidatorClientError>
where where
@@ -249,13 +227,6 @@ impl<C> Client<C> {
Ok(self.nymd.get_reward_pool().await?.u128()) Ok(self.nymd.get_reward_pool().await?.u128())
} }
pub async fn get_current_interval(&self) -> Result<Interval, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_current_interval().await?)
}
pub async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError> pub async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -270,136 +241,14 @@ impl<C> Client<C> {
Ok(self.nymd.get_sybil_resistance_percent().await?) Ok(self.nymd.get_sybil_resistance_percent().await?)
} }
pub async fn get_active_set_work_factor(&self) -> Result<u8, ValidatorClientError> pub async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
{ {
Ok(self.nymd.get_active_set_work_factor().await?) Ok(self.nymd.get_epoch_reward_percent().await?)
}
pub async fn get_interval_reward_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_interval_reward_percent().await?)
}
pub async fn get_current_rewarded_set_update_details(
&self,
) -> Result<RewardedSetUpdateDetails, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self
.nymd
.query_current_rewarded_set_update_details()
.await?)
} }
// basically handles paging for us // basically handles paging for us
pub async fn get_all_nymd_rewarded_set_mixnode_identities(
&self,
) -> Result<Vec<(IdentityKey, RewardedSetNodeStatus)>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
let mut identities = Vec::new();
let mut start_after = None;
let mut height = None;
loop {
let mut paged_response = self
.nymd
.get_rewarded_set_identities_paged(
start_after.take(),
self.rewarded_set_page_limit,
height,
)
.await?;
identities.append(&mut paged_response.identities);
if height.is_none() {
// keep using the same height (the first query happened at the most recent height)
height = Some(paged_response.at_height)
}
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(identities)
}
pub async fn get_nymd_rewarded_and_active_sets(
&self,
) -> Result<Vec<(MixNodeBond, RewardedSetNodeStatus)>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
let rewarded_set_identities = self
.get_all_nymd_rewarded_set_mixnode_identities()
.await?
.into_iter()
.collect::<HashMap<_, _>>();
Ok(all_mixnodes
.into_iter()
.filter_map(|node| {
rewarded_set_identities
.get(node.identity())
.map(|status| (node, *status))
})
.collect())
}
/// If you need both rewarded and the active set, consider using [Self::get_nymd_rewarded_and_active_sets] instead
pub async fn get_nymd_rewarded_set(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
let rewarded_set_identities = self
.get_all_nymd_rewarded_set_mixnode_identities()
.await?
.into_iter()
.map(|(identity, _status)| identity)
.collect::<HashSet<_>>();
Ok(all_mixnodes
.into_iter()
.filter(|node| rewarded_set_identities.contains(node.identity()))
.collect())
}
/// If you need both rewarded and the active set, consider using [Self::get_nymd_rewarded_and_active_sets] instead
pub async fn get_nymd_active_set(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
let all_mixnodes = self.get_all_nymd_mixnodes().await?;
let active_set_identities = self
.get_all_nymd_rewarded_set_mixnode_identities()
.await?
.into_iter()
.filter_map(|(identity, status)| {
if status.is_active() {
Some(identity)
} else {
None
}
})
.collect::<HashSet<_>>();
Ok(all_mixnodes
.into_iter()
.filter(|node| active_set_identities.contains(node.identity()))
.collect())
}
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -448,8 +297,8 @@ impl<C> Client<C> {
pub async fn get_all_nymd_single_mixnode_delegations( pub async fn get_all_nymd_single_mixnode_delegations(
&self, &self,
identity: IdentityKey, identity: mixnet_contract::IdentityKey,
) -> Result<Vec<Delegation>, ValidatorClientError> ) -> Result<Vec<mixnet_contract::Delegation>, ValidatorClientError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
{ {
@@ -571,12 +420,6 @@ impl ApiClient {
Ok(self.validator_api.get_active_mixnodes().await?) Ok(self.validator_api.get_active_mixnodes().await?)
} }
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes().await?)
}
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> { pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_mixnodes().await?) Ok(self.validator_api.get_mixnodes().await?)
} }
@@ -585,55 +428,6 @@ impl ApiClient {
Ok(self.validator_api.get_gateways().await?) Ok(self.validator_api.get_gateways().await?)
} }
pub async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
since: Option<i64>,
) -> Result<CoreNodeStatusResponse, ValidatorClientError> {
Ok(self
.validator_api
.get_gateway_core_status_count(identity, since)
.await?)
}
pub async fn get_mixnode_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
since: Option<i64>,
) -> Result<CoreNodeStatusResponse, ValidatorClientError> {
Ok(self
.validator_api
.get_mixnode_core_status_count(identity, since)
.await?)
}
pub async fn get_mixnode_status(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
Ok(self.validator_api.get_mixnode_status(identity).await?)
}
pub async fn get_mixnode_reward_estimation(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<RewardEstimationResponse, ValidatorClientError> {
Ok(self
.validator_api
.get_mixnode_reward_estimation(identity)
.await?)
}
pub async fn get_mixnode_stake_saturation(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<StakeSaturationResponse, ValidatorClientError> {
Ok(self
.validator_api
.get_mixnode_stake_saturation(identity)
.await?)
}
pub async fn blind_sign( pub async fn blind_sign(
&self, &self,
request_body: &BlindSignRequestBody, request_body: &BlindSignRequestBody,
@@ -9,7 +9,6 @@ pub mod validator_api;
pub use crate::client::ApiClient; pub use crate::client::ApiClient;
pub use crate::error::ValidatorClientError; pub use crate::error::ValidatorClientError;
pub use validator_api_requests::*;
#[cfg(feature = "nymd-client")] #[cfg(feature = "nymd-client")]
pub use client::{Client, Config}; pub use client::{Client, Config};
@@ -13,7 +13,6 @@ use cosmrs::proto::cosmos::auth::v1beta1::{
}; };
use cosmrs::proto::cosmos::bank::v1beta1::{ use cosmrs::proto::cosmos::bank::v1beta1::{
QueryAllBalancesRequest, QueryAllBalancesResponse, QueryBalanceRequest, QueryBalanceResponse, QueryAllBalancesRequest, QueryAllBalancesResponse, QueryBalanceRequest, QueryBalanceResponse,
QueryTotalSupplyRequest, QueryTotalSupplyResponse,
}; };
use cosmrs::proto::cosmos::tx::v1beta1::{ use cosmrs::proto::cosmos::tx::v1beta1::{
SimulateRequest, SimulateResponse as ProtoSimulateResponse, SimulateRequest, SimulateResponse as ProtoSimulateResponse,
@@ -28,7 +27,6 @@ use cosmrs::tendermint::abci::Code as AbciCode;
use cosmrs::tendermint::abci::Transaction; use cosmrs::tendermint::abci::Transaction;
use cosmrs::tendermint::{abci, block, chain}; use cosmrs::tendermint::{abci, block, chain};
use cosmrs::{tx, AccountId, Coin, Denom, Tx}; use cosmrs::{tx, AccountId, Coin, Denom, Tx};
use cosmwasm_std::Coin as CosmWasmCoin;
use prost::Message; use prost::Message;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
@@ -164,43 +162,6 @@ pub trait CosmWasmClient: rpc::Client {
.map_err(|_| NymdError::SerializationError("Coins".to_owned())) .map_err(|_| NymdError::SerializationError("Coins".to_owned()))
} }
// this is annoyingly and inconsistently returning `Vec<CosmWasmCoin>` rather than
// Vec<Coin>, since cosmrs::Coin can't deal with IBC denoms.
// Presumably after https://github.com/cosmos/cosmos-rust/issues/173 is resolved,
// the code could be adjusted
async fn get_total_supply(&self) -> Result<Vec<CosmWasmCoin>, NymdError> {
let path = Some("/cosmos.bank.v1beta1.Query/TotalSupply".parse().unwrap());
let mut supply = Vec::new();
let mut pagination = None;
loop {
let req = QueryTotalSupplyRequest { pagination };
let mut res = self
.make_abci_query::<_, QueryTotalSupplyResponse>(path.clone(), req)
.await?;
supply.append(&mut res.supply);
if let Some(pagination_info) = res.pagination {
pagination = Some(create_pagination(pagination_info.next_key))
} else {
break;
}
}
supply
.into_iter()
.map(|coin| {
coin.amount.parse().map(|amount| CosmWasmCoin {
denom: coin.denom,
amount,
})
})
.collect::<Result<_, _>>()
.map_err(|_| NymdError::SerializationError("Coins".to_owned()))
}
async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NymdError> { async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NymdError> {
Ok(self.tx(id, false).await?) Ok(self.tx(id, false).await?)
} }
@@ -160,7 +160,10 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
{ {
let init_msg = cosmwasm::MsgInstantiateContract { let init_msg = cosmwasm::MsgInstantiateContract {
sender: sender_address.clone(), sender: sender_address.clone(),
admin: options.as_mut().and_then(|options| options.admin.take()), admin: options
.as_mut()
.map(|options| options.admin.take())
.flatten(),
code_id, code_id,
// now this is a weird one. the protobuf files say this field is optional, // now this is a weird one. the protobuf files say this field is optional,
// but if you omit it, the initialisation will fail CheckTx // but if you omit it, the initialisation will fail CheckTx
@@ -20,7 +20,6 @@ pub enum Operation {
BondMixnodeOnBehalf, BondMixnodeOnBehalf,
UnbondMixnode, UnbondMixnode,
UnbondMixnodeOnBehalf, UnbondMixnodeOnBehalf,
UpdateMixnodeConfig,
DelegateToMixnode, DelegateToMixnode,
DelegateToMixnodeOnBehalf, DelegateToMixnodeOnBehalf,
UndelegateFromMixnode, UndelegateFromMixnode,
@@ -41,10 +40,6 @@ pub enum Operation {
WithdrawVestedCoins, WithdrawVestedCoins,
TrackUndelegation, TrackUndelegation,
CreatePeriodicVestingAccount, CreatePeriodicVestingAccount,
AdvanceCurrentInterval,
WriteRewardedSet,
ClearRewardedSet,
} }
pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin { pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin {
@@ -62,7 +57,6 @@ impl fmt::Display for Operation {
Operation::BondMixnode => f.write_str("BondMixnode"), Operation::BondMixnode => f.write_str("BondMixnode"),
Operation::BondMixnodeOnBehalf => f.write_str("BondMixnodeOnBehalf"), Operation::BondMixnodeOnBehalf => f.write_str("BondMixnodeOnBehalf"),
Operation::UnbondMixnode => f.write_str("UnbondMixnode"), Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
Operation::UpdateMixnodeConfig => f.write_str("UpdateMixnodeConfig"),
Operation::UnbondMixnodeOnBehalf => f.write_str("UnbondMixnodeOnBehalf"), Operation::UnbondMixnodeOnBehalf => f.write_str("UnbondMixnodeOnBehalf"),
Operation::BondGateway => f.write_str("BondGateway"), Operation::BondGateway => f.write_str("BondGateway"),
Operation::BondGatewayOnBehalf => f.write_str("BondGatewayOnBehalf"), Operation::BondGatewayOnBehalf => f.write_str("BondGatewayOnBehalf"),
@@ -82,9 +76,6 @@ impl fmt::Display for Operation {
Operation::WithdrawVestedCoins => f.write_str("WithdrawVestedCoins"), Operation::WithdrawVestedCoins => f.write_str("WithdrawVestedCoins"),
Operation::TrackUndelegation => f.write_str("TrackUndelegation"), Operation::TrackUndelegation => f.write_str("TrackUndelegation"),
Operation::CreatePeriodicVestingAccount => f.write_str("CreatePeriodicVestingAccount"), Operation::CreatePeriodicVestingAccount => f.write_str("CreatePeriodicVestingAccount"),
Operation::AdvanceCurrentInterval => f.write_str("AdvanceCurrentInterval"),
Operation::WriteRewardedSet => f.write_str("WriteRewardedSet"),
Operation::ClearRewardedSet => f.write_str("ClearRewardedSet"),
} }
} }
} }
@@ -103,7 +94,6 @@ impl Operation {
Operation::BondMixnodeOnBehalf => 200_000u64.into(), Operation::BondMixnodeOnBehalf => 200_000u64.into(),
Operation::UnbondMixnode => 175_000u64.into(), Operation::UnbondMixnode => 175_000u64.into(),
Operation::UnbondMixnodeOnBehalf => 175_000u64.into(), Operation::UnbondMixnodeOnBehalf => 175_000u64.into(),
Operation::UpdateMixnodeConfig => 175_000u64.into(),
Operation::DelegateToMixnode => 175_000u64.into(), Operation::DelegateToMixnode => 175_000u64.into(),
Operation::DelegateToMixnodeOnBehalf => 175_000u64.into(), Operation::DelegateToMixnodeOnBehalf => 175_000u64.into(),
Operation::UndelegateFromMixnode => 175_000u64.into(), Operation::UndelegateFromMixnode => 175_000u64.into(),
@@ -122,9 +112,6 @@ impl Operation {
Operation::WithdrawVestedCoins => 175_000u64.into(), Operation::WithdrawVestedCoins => 175_000u64.into(),
Operation::TrackUndelegation => 175_000u64.into(), Operation::TrackUndelegation => 175_000u64.into(),
Operation::CreatePeriodicVestingAccount => 175_000u64.into(), Operation::CreatePeriodicVestingAccount => 175_000u64.into(),
Operation::AdvanceCurrentInterval => 175_000u64.into(),
Operation::WriteRewardedSet => 175_000u64.into(),
Operation::ClearRewardedSet => 175_000u64.into(),
} }
} }
@@ -13,12 +13,12 @@ use cosmrs::rpc::{Error as TendermintRpcError, HttpClientUrl};
use cosmwasm_std::{Coin, Uint128}; use cosmwasm_std::{Coin, Uint128};
pub use fee::gas_price::GasPrice; pub use fee::gas_price::GasPrice;
use fee::helpers::Operation; use fee::helpers::Operation;
use mixnet_contract_common::{ use mixnet_contract::{
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayOwnershipResponse, ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayOwnershipResponse,
IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond, MixOwnershipResponse, IdentityKey, LayerDistribution, MixNode, MixNodeBond, MixOwnershipResponse,
MixnetContractVersion, MixnodeRewardingStatusResponse, PagedAllDelegationsResponse, MixnetContractVersion, MixnodeRewardingStatusResponse, PagedAllDelegationsResponse,
PagedDelegatorDelegationsResponse, PagedGatewayResponse, PagedMixDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse, PagedMixDelegationsResponse,
PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails, PagedMixnodeResponse, QueryMsg, RewardingIntervalResponse,
}; };
use serde::Serialize; use serde::Serialize;
use std::convert::TryInto; use std::convert::TryInto;
@@ -27,12 +27,9 @@ pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient; pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
pub use crate::nymd::fee::Fee; pub use crate::nymd::fee::Fee;
use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER; use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER;
pub use cosmrs::rpc::endpoint::validators::Response as ValidatorResponse;
pub use cosmrs::rpc::HttpClient as QueryNymdClient; pub use cosmrs::rpc::HttpClient as QueryNymdClient;
pub use cosmrs::rpc::Paging;
pub use cosmrs::tendermint::block::Height; pub use cosmrs::tendermint::block::Height;
pub use cosmrs::tendermint::hash; pub use cosmrs::tendermint::hash;
pub use cosmrs::tendermint::validator::Info as TendermintValidatorInfo;
pub use cosmrs::tendermint::Time as TendermintTime; pub use cosmrs::tendermint::Time as TendermintTime;
pub use cosmrs::tx::{self, Gas}; pub use cosmrs::tx::{self, Gas};
pub use cosmrs::Coin as CosmosCoin; pub use cosmrs::Coin as CosmosCoin;
@@ -60,16 +57,16 @@ pub struct NymdClient<C> {
impl NymdClient<QueryNymdClient> { impl NymdClient<QueryNymdClient> {
pub fn connect<U>( pub fn connect<U>(
endpoint: U, endpoint: U,
mixnet_contract_address: Option<AccountId>, mixnet_contract_address: AccountId,
vesting_contract_address: Option<AccountId>, vesting_contract_address: AccountId,
) -> Result<NymdClient<QueryNymdClient>, NymdError> ) -> Result<NymdClient<QueryNymdClient>, NymdError>
where where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>, U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{ {
Ok(NymdClient { Ok(NymdClient {
client: QueryNymdClient::new(endpoint)?, client: QueryNymdClient::new(endpoint)?,
mixnet_contract_address, mixnet_contract_address: Some(mixnet_contract_address),
vesting_contract_address, vesting_contract_address: Some(vesting_contract_address),
client_address: None, client_address: None,
custom_gas_limits: Default::default(), custom_gas_limits: Default::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
@@ -237,17 +234,6 @@ impl<C> NymdClient<C> {
.map(|block| block.block_id.hash) .map(|block| block.block_id.hash)
} }
pub async fn get_validators(
&self,
height: u64,
paging: Paging,
) -> Result<ValidatorResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
Ok(self.client.validators(height as u32, paging).await?)
}
pub async fn get_balance( pub async fn get_balance(
&self, &self,
address: &AccountId, address: &AccountId,
@@ -269,13 +255,6 @@ impl<C> NymdClient<C> {
self.get_balance(address, self.denom()?).await self.get_balance(address, self.denom()?).await
} }
pub async fn get_total_supply(&self) -> Result<Vec<Coin>, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.get_total_supply().await
}
pub async fn get_contract_settings(&self) -> Result<ContractStateParams, NymdError> pub async fn get_contract_settings(&self) -> Result<ContractStateParams, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -296,65 +275,35 @@ impl<C> NymdClient<C> {
.await .await
} }
pub async fn get_current_rewarding_interval(
&self,
) -> Result<RewardingIntervalResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::CurrentRewardingInterval {};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
.await
}
pub async fn get_rewarding_status( pub async fn get_rewarding_status(
&self, &self,
mix_identity: mixnet_contract_common::IdentityKey, mix_identity: mixnet_contract::IdentityKey,
interval_id: u32, rewarding_interval_nonce: u32,
) -> Result<MixnodeRewardingStatusResponse, NymdError> ) -> Result<MixnodeRewardingStatusResponse, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
{ {
let request = QueryMsg::GetRewardingStatus { let request = QueryMsg::GetRewardingStatus {
mix_identity, mix_identity,
interval_id, rewarding_interval_nonce,
}; };
self.client self.client
.query_contract_smart(self.mixnet_contract_address()?, &request) .query_contract_smart(self.mixnet_contract_address()?, &request)
.await .await
} }
pub async fn query_current_rewarded_set_height(&self) -> Result<u64, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetCurrentRewardedSetHeight {};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
.await
}
pub async fn query_current_rewarded_set_update_details(
&self,
) -> Result<RewardedSetUpdateDetails, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetRewardedSetUpdateDetails {};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
.await
}
pub async fn get_rewarded_set_identities_paged(
&self,
start_after: Option<IdentityKey>,
page_limit: Option<u32>,
height: Option<u64>,
) -> Result<PagedRewardedSetResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetRewardedSet {
height,
start_after,
limit: page_limit,
};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
.await
}
pub async fn get_layer_distribution(&self) -> Result<LayerDistribution, NymdError> pub async fn get_layer_distribution(&self) -> Result<LayerDistribution, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -365,16 +314,6 @@ impl<C> NymdClient<C> {
.await .await
} }
pub async fn get_current_interval(&self) -> Result<Interval, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetCurrentInterval {};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
.await
}
pub async fn get_reward_pool(&self) -> Result<Uint128, NymdError> pub async fn get_reward_pool(&self) -> Result<Uint128, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
@@ -405,21 +344,11 @@ impl<C> NymdClient<C> {
.await .await
} }
pub async fn get_active_set_work_factor(&self) -> Result<u8, NymdError> pub async fn get_epoch_reward_percent(&self) -> Result<u8, NymdError>
where where
C: CosmWasmClient + Sync, C: CosmWasmClient + Sync,
{ {
let request = QueryMsg::GetActiveSetWorkFactor {}; let request = QueryMsg::GetEpochRewardPercent {};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
.await
}
pub async fn get_interval_reward_percent(&self) -> Result<u8, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetIntervalRewardPercent {};
self.client self.client
.query_contract_smart(self.mixnet_contract_address()?, &request) .query_contract_smart(self.mixnet_contract_address()?, &request)
.await .await
@@ -844,31 +773,6 @@ impl<C> NymdClient<C> {
.await .await
} }
/// Update the configuration of a mixnode. Right now, only possible for profit margin.
pub async fn update_mixnode_config(
&self,
profit_margin_percent: u8,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.operation_fee(Operation::UpdateMixnodeConfig);
let req = ExecuteMsg::UpdateMixnodeConfig {
profit_margin_percent,
};
self.client
.execute(
self.address(),
self.mixnet_contract_address()?,
&req,
fee,
"Updating mixnode configuration from rust!",
Vec::new(),
)
.await
}
/// Delegates specified amount of stake to particular mixnode. /// Delegates specified amount of stake to particular mixnode.
pub async fn delegate_to_mixnode( pub async fn delegate_to_mixnode(
&self, &self,
@@ -1172,38 +1076,17 @@ impl<C> NymdClient<C> {
.await .await
} }
pub async fn advance_current_interval(&self) -> Result<ExecuteResult, NymdError> pub async fn begin_mixnode_rewarding(
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.operation_fee(Operation::AdvanceCurrentInterval);
let req = ExecuteMsg::AdvanceCurrentInterval {};
self.client
.execute(
self.address(),
self.mixnet_contract_address()?,
&req,
fee,
"Advancing current interval",
Vec::new(),
)
.await
}
pub async fn write_rewarded_set(
&self, &self,
rewarded_set: Vec<IdentityKey>, rewarding_interval_nonce: u32,
expected_active_set_size: u32,
) -> Result<ExecuteResult, NymdError> ) -> Result<ExecuteResult, NymdError>
where where
C: SigningCosmWasmClient + Sync, C: SigningCosmWasmClient + Sync,
{ {
let fee = self.operation_fee(Operation::WriteRewardedSet); let fee = self.operation_fee(Operation::BeginMixnodeRewarding);
let req = ExecuteMsg::WriteRewardedSet { let req = ExecuteMsg::BeginMixnodeRewarding {
rewarded_set, rewarding_interval_nonce,
expected_active_set_size,
}; };
self.client self.client
.execute( .execute(
@@ -1211,7 +1094,31 @@ impl<C> NymdClient<C> {
self.mixnet_contract_address()?, self.mixnet_contract_address()?,
&req, &req,
fee, fee,
"Writing rewarded set", "Beginning mixnode rewarding procedure",
Vec::new(),
)
.await
}
pub async fn finish_mixnode_rewarding(
&self,
rewarding_interval_nonce: u32,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.operation_fee(Operation::FinishMixnodeRewarding);
let req = ExecuteMsg::FinishMixnodeRewarding {
rewarding_interval_nonce,
};
self.client
.execute(
self.address(),
self.mixnet_contract_address()?,
&req,
fee,
"Finishing mixnode rewarding procedure",
Vec::new(), Vec::new(),
) )
.await .await
@@ -8,7 +8,7 @@ use crate::nymd::fee::helpers::Operation;
use crate::nymd::{cosmwasm_coin_to_cosmos_coin, NymdClient}; use crate::nymd::{cosmwasm_coin_to_cosmos_coin, NymdClient};
use async_trait::async_trait; use async_trait::async_trait;
use cosmwasm_std::Coin; use cosmwasm_std::Coin;
use mixnet_contract_common::{Gateway, IdentityKey, IdentityKeyRef, MixNode}; use mixnet_contract::{Gateway, IdentityKey, IdentityKeyRef, MixNode};
use vesting_contract::messages::ExecuteMsg as VestingExecuteMsg; use vesting_contract::messages::ExecuteMsg as VestingExecuteMsg;
#[async_trait] #[async_trait]
@@ -64,8 +64,7 @@ pub trait VestingSigningClient {
async fn create_periodic_vesting_account( async fn create_periodic_vesting_account(
&self, &self,
owner_address: &str, address: &str,
staking_address: Option<String>,
start_time: Option<u64>, start_time: Option<u64>,
amount: Coin, amount: Coin,
) -> Result<ExecuteResult, NymdError>; ) -> Result<ExecuteResult, NymdError>;
@@ -272,15 +271,13 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
} }
async fn create_periodic_vesting_account( async fn create_periodic_vesting_account(
&self, &self,
owner_address: &str, address: &str,
staking_address: Option<String>,
start_time: Option<u64>, start_time: Option<u64>,
amount: Coin, amount: Coin,
) -> Result<ExecuteResult, NymdError> { ) -> Result<ExecuteResult, NymdError> {
let fee = self.operation_fee(Operation::CreatePeriodicVestingAccount); let fee = self.operation_fee(Operation::CreatePeriodicVestingAccount);
let req = VestingExecuteMsg::CreateAccount { let req = VestingExecuteMsg::CreateAccount {
owner_address: owner_address.to_string(), address: address.to_string(),
staking_address,
start_time, start_time,
}; };
self.client self.client
@@ -133,7 +133,6 @@ impl DirectSecp256k1HdWallet {
} }
} }
#[must_use]
pub struct DirectSecp256k1HdWalletBuilder { pub struct DirectSecp256k1HdWalletBuilder {
/// The password to use when deriving a BIP39 seed from a mnemonic. /// The password to use when deriving a BIP39 seed from a mnemonic.
bip39_password: String, bip39_password: String,
@@ -203,28 +202,14 @@ impl DirectSecp256k1HdWalletBuilder {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use network_defaults::BECH32_PREFIX;
#[test] #[test]
fn generating_account_addresses() { fn generating_account_addresses() {
let (addr1, addr2, addr3) = match BECH32_PREFIX {
"punk" => (
"punk1jw6mp7d5xqc7w6xm79lha27glmd0vdt32a3fj2",
"punk1h5hgn94nsq4kh99rjj794hr5h5q6yfm22mcqqn",
"punk17n9flp6jflljg6fp05dsy07wcprf2uuujse962",
),
"nymt" => (
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
),
_ => panic!("Test needs to be updated with new bech32 prefix"),
};
// test vectors produced from our js wallet // test vectors produced from our js wallet
let mnemonic_address = vec![ let mnemonic_address = vec![
("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", addr1), ("crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove", "nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94"),
("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", addr2), ("acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel", "nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv"),
("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", addr3) ("step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball", "nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4")
]; ];
for (mnemonic, address) in mnemonic_address.into_iter() { for (mnemonic, address) in mnemonic_address.into_iter() {
@@ -1,25 +1,16 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::validator_api::error::ValidatorAPIError; use crate::validator_api::error::ValidatorAPIError;
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse}; use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond}; use mixnet_contract::{GatewayBond, MixNodeBond};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url; use url::Url;
use validator_api_requests::models::{
CoreNodeStatusResponse, InclusionProbabilityResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
pub mod error; pub mod error;
pub(crate) mod routes; pub(crate) mod routes;
type PathSegments<'a> = &'a [&'a str]; type PathSegments<'a> = &'a [&'a str];
type Params<'a, K, V> = &'a [(K, V)];
const NO_PARAMS: Params<'_, &'_ str, &'_ str> = &[];
pub struct Client { pub struct Client {
url: Url, url: Url,
@@ -39,33 +30,24 @@ impl Client {
self.url = new_url self.url = new_url
} }
async fn query_validator_api<T, K, V>( async fn query_validator_api<T>(&self, path: PathSegments<'_>) -> Result<T, ValidatorAPIError>
&self,
path: PathSegments<'_>,
params: Params<'_, K, V>,
) -> Result<T, ValidatorAPIError>
where where
for<'a> T: Deserialize<'a>, for<'a> T: Deserialize<'a>,
K: AsRef<str>,
V: AsRef<str>,
{ {
let url = create_api_url(&self.url, path, params); let url = create_api_url(&self.url, path);
Ok(self.reqwest_client.get(url).send().await?.json().await?) Ok(self.reqwest_client.get(url).send().await?.json().await?)
} }
async fn post_validator_api<B, T, K, V>( async fn post_validator_api<B, T>(
&self, &self,
path: PathSegments<'_>, path: PathSegments<'_>,
params: Params<'_, K, V>,
json_body: &B, json_body: &B,
) -> Result<T, ValidatorAPIError> ) -> Result<T, ValidatorAPIError>
where where
B: Serialize + ?Sized, B: Serialize + ?Sized,
for<'a> T: Deserialize<'a>, for<'a> T: Deserialize<'a>,
K: AsRef<str>,
V: AsRef<str>,
{ {
let url = create_api_url(&self.url, path, params); let url = create_api_url(&self.url, path);
Ok(self Ok(self
.reqwest_client .reqwest_client
.post(url) .post(url)
@@ -77,176 +59,18 @@ impl Client {
} }
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> { pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS) self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES])
.await .await
} }
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> { pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS) self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS])
.await .await
} }
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> { pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
self.query_validator_api( self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE])
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
NO_PARAMS,
)
.await
}
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
self.query_validator_api(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
NO_PARAMS,
)
.await
}
pub async fn get_probs_mixnode_rewarded(
&self,
mixnode_id: &str,
) -> Result<HashMap<String, f32>, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::MIXNODES,
routes::REWARDED,
routes::INCLUSION_CHANCE,
mixnode_id,
],
NO_PARAMS,
)
.await
}
pub async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
since: Option<i64>,
) -> Result<CoreNodeStatusResponse, ValidatorAPIError> {
if let Some(since) = since {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::GATEWAY,
identity,
CORE_STATUS_COUNT,
],
&[(SINCE_ARG, since.to_string())],
)
.await .await
} else {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::GATEWAY,
identity,
],
NO_PARAMS,
)
.await
}
}
pub async fn get_mixnode_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
since: Option<i64>,
) -> Result<CoreNodeStatusResponse, ValidatorAPIError> {
if let Some(since) = since {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
identity,
CORE_STATUS_COUNT,
],
&[(SINCE_ARG, since.to_string())],
)
.await
} else {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
identity,
],
NO_PARAMS,
)
.await
}
}
pub async fn get_mixnode_status(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<MixnodeStatusResponse, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
identity,
routes::STATUS,
],
NO_PARAMS,
)
.await
}
pub async fn get_mixnode_reward_estimation(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<RewardEstimationResponse, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
identity,
routes::REWARD_ESTIMATION,
],
NO_PARAMS,
)
.await
}
pub async fn get_mixnode_stake_saturation(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<StakeSaturationResponse, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
identity,
routes::STAKE_SATURATION,
],
NO_PARAMS,
)
.await
}
pub async fn get_mixnode_inclusion_probability(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<InclusionProbabilityResponse, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
identity,
routes::INCLUSION_CHANCE,
],
NO_PARAMS,
)
.await
} }
pub async fn blind_sign( pub async fn blind_sign(
@@ -255,7 +79,6 @@ impl Client {
) -> Result<BlindedSignatureResponse, ValidatorAPIError> { ) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
self.post_validator_api( self.post_validator_api(
&[routes::API_VERSION, routes::COCONUT_BLIND_SIGN], &[routes::API_VERSION, routes::COCONUT_BLIND_SIGN],
NO_PARAMS,
request_body, request_body,
) )
.await .await
@@ -264,20 +87,13 @@ impl Client {
pub async fn get_coconut_verification_key( pub async fn get_coconut_verification_key(
&self, &self,
) -> Result<VerificationKeyResponse, ValidatorAPIError> { ) -> Result<VerificationKeyResponse, ValidatorAPIError> {
self.query_validator_api( self.query_validator_api(&[routes::API_VERSION, routes::COCONUT_VERIFICATION_KEY])
&[routes::API_VERSION, routes::COCONUT_VERIFICATION_KEY], .await
NO_PARAMS,
)
.await
} }
} }
// utility function that should solve the double slash problem in validator API forever. // utility function that should solve the double slash problem in validator API forever.
fn create_api_url<K: AsRef<str>, V: AsRef<str>>( fn create_api_url(base: &Url, segments: PathSegments<'_>) -> Url {
base: &Url,
segments: PathSegments<'_>,
params: Params<'_, K, V>,
) -> Url {
let mut url = base.clone(); let mut url = base.clone();
let mut path_segments = url let mut path_segments = url
.path_segments_mut() .path_segments_mut()
@@ -292,10 +108,6 @@ fn create_api_url<K: AsRef<str>, V: AsRef<str>>(
// and can be dropped // and can be dropped
drop(path_segments); drop(path_segments);
if !params.is_empty() {
url.query_pairs_mut().extend_pairs(params);
}
url url
} }
@@ -310,66 +122,51 @@ mod tests {
// works with 1 segment // works with 1 segment
assert_eq!( assert_eq!(
"http://foomp.com/foo", "http://foomp.com/foo",
create_api_url(&base_url, &["foo"], NO_PARAMS).as_str() create_api_url(&base_url, &["foo"]).as_str()
); );
// works with 2 segments // works with 2 segments
assert_eq!( assert_eq!(
"http://foomp.com/foo/bar", "http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo", "bar"], NO_PARAMS).as_str() create_api_url(&base_url, &["foo", "bar"]).as_str()
); );
// works with leading slash // works with leading slash
assert_eq!( assert_eq!(
"http://foomp.com/foo", "http://foomp.com/foo",
create_api_url(&base_url, &["/foo"], NO_PARAMS).as_str() create_api_url(&base_url, &["/foo"]).as_str()
); );
assert_eq!( assert_eq!(
"http://foomp.com/foo/bar", "http://foomp.com/foo/bar",
create_api_url(&base_url, &["/foo", "bar"], NO_PARAMS).as_str() create_api_url(&base_url, &["/foo", "bar"]).as_str()
); );
assert_eq!( assert_eq!(
"http://foomp.com/foo/bar", "http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo", "/bar"], NO_PARAMS).as_str() create_api_url(&base_url, &["foo", "/bar"]).as_str()
); );
// works with trailing slash // works with trailing slash
assert_eq!( assert_eq!(
"http://foomp.com/foo", "http://foomp.com/foo",
create_api_url(&base_url, &["foo/"], NO_PARAMS).as_str() create_api_url(&base_url, &["foo/"]).as_str()
); );
assert_eq!( assert_eq!(
"http://foomp.com/foo/bar", "http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo/", "bar"], NO_PARAMS).as_str() create_api_url(&base_url, &["foo/", "bar"]).as_str()
); );
assert_eq!( assert_eq!(
"http://foomp.com/foo/bar", "http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo", "bar/"], NO_PARAMS).as_str() create_api_url(&base_url, &["foo", "bar/"]).as_str()
); );
// works with both leading and trailing slash // works with both leading and trailing slash
assert_eq!( assert_eq!(
"http://foomp.com/foo", "http://foomp.com/foo",
create_api_url(&base_url, &["/foo/"], NO_PARAMS).as_str() create_api_url(&base_url, &["/foo/"]).as_str()
); );
assert_eq!( assert_eq!(
"http://foomp.com/foo/bar", "http://foomp.com/foo/bar",
create_api_url(&base_url, &["/foo/", "/bar/"], NO_PARAMS).as_str() create_api_url(&base_url, &["/foo/", "/bar/"]).as_str()
);
// adds params
assert_eq!(
"http://foomp.com/foo/bar?foomp=baz",
create_api_url(&base_url, &["foo", "bar"], &[("foomp", "baz")]).as_str()
);
assert_eq!(
"http://foomp.com/foo/bar?arg1=val1&arg2=val2",
create_api_url(
&base_url,
&["/foo/", "/bar/"],
&[("arg1", "val1"), ("arg2", "val2")]
)
.as_str()
); );
} }
} }
@@ -8,19 +8,6 @@ pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways"; pub const GATEWAYS: &str = "gateways";
pub const ACTIVE: &str = "active"; pub const ACTIVE: &str = "active";
pub const REWARDED: &str = "rewarded";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign"; pub const COCONUT_BLIND_SIGN: &str = "blind_sign";
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key"; pub const COCONUT_VERIFICATION_KEY: &str = "verification_key";
pub const STATUS_ROUTES: &str = "status";
pub const MIXNODE: &str = "mixnode";
pub const GATEWAY: &str = "gateway";
pub const CORE_STATUS_COUNT: &str = "core-status-count";
pub const SINCE_ARG: &str = "since";
pub const STATUS: &str = "status";
pub const REWARD_ESTIMATION: &str = "reward-estimation";
pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
@@ -1,10 +0,0 @@
[package]
name = "contracts-common"
version = "0.1.0"
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0-beta3"
@@ -1,30 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::Event;
/// Looks up value of particular attribute in the provided event. If it fails to find it,
/// the function panics.
///
/// # Arguments
///
/// * `event`: event to search through.
/// * `key`: key associated with the particular attribute
pub fn must_find_attribute(event: &Event, key: &str) -> String {
may_find_attribute(event, key).unwrap()
}
/// Looks up value of particular attribute in the provided event. Returns None if it does not exist.
///
/// # Arguments
///
/// * `event`: event to search through.
/// * `key`: key associated with the particular attribute
pub fn may_find_attribute(event: &Event, key: &str) -> Option<String> {
for attr in &event.attributes {
if attr.key == key {
return Some(attr.value.clone());
}
}
None
}
@@ -1,4 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod events;
@@ -1,338 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::mixnode::NodeRewardResult;
use crate::{ContractStateParams, Delegation, IdentityKeyRef, Interval, Layer};
use cosmwasm_std::{Addr, Coin, Event, Uint128};
pub use contracts_common::events::*;
// event types
pub const DELEGATION_EVENT_TYPE: &str = "delegation";
pub const UNDELEGATION_EVENT_TYPE: &str = "undelegation";
pub const GATEWAY_BONDING_EVENT_TYPE: &str = "gateway_bonding";
pub const GATEWAY_UNBONDING_EVENT_TYPE: &str = "gateway_unbonding";
pub const MIXNODE_BONDING_EVENT_TYPE: &str = "mixnode_bonding";
pub const MIXNODE_UNBONDING_EVENT_TYPE: &str = "mixnode_unbonding";
pub const SETTINGS_UPDATE_EVENT_TYPE: &str = "settings_update";
pub const OPERATOR_REWARDING_EVENT_TYPE: &str = "mix_rewarding";
pub const MIX_DELEGATORS_REWARDING_EVENT_TYPE: &str = "mix_delegators_rewarding";
pub const CHANGE_REWARDED_SET_EVENT_TYPE: &str = "change_rewarded_set";
pub const ADVANCE_INTERVAL_EVENT_TYPE: &str = "advance_interval";
// attributes that are used in multiple places
pub const OWNER_KEY: &str = "owner";
pub const AMOUNT_KEY: &str = "amount";
pub const PROXY_KEY: &str = "proxy";
// event-specific attributes
// delegation/undelegation
pub const DELEGATOR_KEY: &str = "delegator";
pub const DELEGATION_TARGET_KEY: &str = "delegation_target";
pub const DELEGATION_HEIGHT_KEY: &str = "delegation_latest_block_height";
// bonding/unbonding
pub const NODE_IDENTITY_KEY: &str = "identity";
pub const ASSIGNED_LAYER_KEY: &str = "assigned_layer";
// settings change
pub const OLD_MINIMUM_MIXNODE_PLEDGE_KEY: &str = "old_minimum_mixnode_pledge";
pub const OLD_MINIMUM_GATEWAY_PLEDGE_KEY: &str = "old_minimum_gateway_pledge";
pub const OLD_MIXNODE_REWARDED_SET_SIZE_KEY: &str = "old_mixnode_rewarded_set_size";
pub const OLD_MIXNODE_ACTIVE_SET_SIZE_KEY: &str = "old_mixnode_active_set_size";
pub const OLD_ACTIVE_SET_WORK_FACTOR_KEY: &str = "old_active_set_work_factor";
pub const NEW_MINIMUM_MIXNODE_PLEDGE_KEY: &str = "new_minimum_mixnode_pledge";
pub const NEW_MINIMUM_GATEWAY_PLEDGE_KEY: &str = "new_minimum_gateway_pledge";
pub const NEW_MIXNODE_REWARDED_SET_SIZE_KEY: &str = "new_mixnode_rewarded_set_size";
pub const NEW_MIXNODE_ACTIVE_SET_SIZE_KEY: &str = "new_mixnode_active_set_size";
// rewarding
pub const INTERVAL_ID_KEY: &str = "interval_id";
pub const TOTAL_MIXNODE_REWARD_KEY: &str = "total_node_reward";
pub const OPERATOR_REWARD_KEY: &str = "operator_reward";
pub const LAMBDA_KEY: &str = "lambda";
pub const SIGMA_KEY: &str = "sigma";
pub const DISTRIBUTED_DELEGATION_REWARDS_KEY: &str = "distributed_delegation_rewards";
pub const FURTHER_DELEGATIONS_TO_REWARD_KEY: &str = "further_delegations";
pub const NO_REWARD_REASON_KEY: &str = "no_reward_reason";
pub const BOND_NOT_FOUND_VALUE: &str = "bond_not_found";
pub const BOND_TOO_FRESH_VALUE: &str = "bond_too_fresh";
pub const ZERO_UPTIME_VALUE: &str = "zero_uptime";
// rewarded set update
pub const ACTIVE_SET_SIZE_KEY: &str = "active_set_size";
pub const REWARDED_SET_SIZE_KEY: &str = "rewarded_set_size";
pub const NODES_IN_REWARDED_SET_KEY: &str = "nodes_in_rewarded_set";
pub const CURRENT_INTERVAL_ID_KEY: &str = "current_interval";
pub const NEW_CURRENT_INTERVAL_KEY: &str = "new_current_interval";
pub fn new_delegation_event(
delegator: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
mix_identity: IdentityKeyRef,
) -> Event {
let mut event = Event::new(DELEGATION_EVENT_TYPE).add_attribute(DELEGATOR_KEY, delegator);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_identity)
}
pub fn new_undelegation_event(
delegator: &Addr,
proxy: &Option<Addr>,
old_delegation: &Delegation,
mix_identity: IdentityKeyRef,
) -> Event {
let mut event = Event::new(UNDELEGATION_EVENT_TYPE).add_attribute(DELEGATOR_KEY, delegator);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event
.add_attribute(AMOUNT_KEY, old_delegation.amount.to_string())
.add_attribute(
DELEGATION_HEIGHT_KEY,
old_delegation.block_height.to_string(),
)
.add_attribute(DELEGATION_TARGET_KEY, mix_identity)
}
pub fn new_gateway_bonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef,
) -> Event {
let mut event = Event::new(GATEWAY_BONDING_EVENT_TYPE)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_gateway_unbonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef,
) -> Event {
let mut event = Event::new(GATEWAY_UNBONDING_EVENT_TYPE)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_mixnode_bonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef,
assigned_layer: Layer,
) -> Event {
let mut event = Event::new(MIXNODE_BONDING_EVENT_TYPE)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event
.add_attribute(ASSIGNED_LAYER_KEY, assigned_layer)
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_mixnode_unbonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef,
) -> Event {
let mut event = Event::new(MIXNODE_UNBONDING_EVENT_TYPE)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity);
if let Some(proxy) = proxy {
event = event.add_attribute(PROXY_KEY, proxy)
}
// coin implements Display trait and we use that implementation here
event.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_settings_update_event(
old_params: &ContractStateParams,
new_params: &ContractStateParams,
) -> Event {
let mut event = Event::new(SETTINGS_UPDATE_EVENT_TYPE);
if old_params.minimum_mixnode_pledge != new_params.minimum_mixnode_pledge {
event = event
.add_attribute(
OLD_MINIMUM_MIXNODE_PLEDGE_KEY,
old_params.minimum_mixnode_pledge,
)
.add_attribute(
NEW_MINIMUM_MIXNODE_PLEDGE_KEY,
new_params.minimum_mixnode_pledge,
)
}
if old_params.minimum_gateway_pledge != new_params.minimum_gateway_pledge {
event = event
.add_attribute(
OLD_MINIMUM_GATEWAY_PLEDGE_KEY,
old_params.minimum_gateway_pledge,
)
.add_attribute(
NEW_MINIMUM_GATEWAY_PLEDGE_KEY,
new_params.minimum_gateway_pledge,
)
}
if old_params.mixnode_rewarded_set_size != new_params.mixnode_rewarded_set_size {
event = event
.add_attribute(
OLD_MIXNODE_REWARDED_SET_SIZE_KEY,
old_params.mixnode_rewarded_set_size.to_string(),
)
.add_attribute(
NEW_MIXNODE_REWARDED_SET_SIZE_KEY,
new_params.mixnode_rewarded_set_size.to_string(),
)
}
if old_params.mixnode_active_set_size != new_params.mixnode_active_set_size {
event = event
.add_attribute(
OLD_MIXNODE_ACTIVE_SET_SIZE_KEY,
old_params.mixnode_active_set_size.to_string(),
)
.add_attribute(
NEW_MIXNODE_ACTIVE_SET_SIZE_KEY,
new_params.mixnode_active_set_size.to_string(),
)
}
event
}
pub fn new_not_found_mix_operator_rewarding_event(
interval_id: u32,
identity: IdentityKeyRef,
) -> Event {
Event::new(OPERATOR_REWARDING_EVENT_TYPE)
.add_attribute(INTERVAL_ID_KEY, interval_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(NO_REWARD_REASON_KEY, BOND_NOT_FOUND_VALUE)
}
pub fn new_too_fresh_bond_mix_operator_rewarding_event(
interval_id: u32,
identity: IdentityKeyRef,
) -> Event {
Event::new(OPERATOR_REWARDING_EVENT_TYPE)
.add_attribute(INTERVAL_ID_KEY, interval_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(NO_REWARD_REASON_KEY, BOND_TOO_FRESH_VALUE)
}
pub fn new_zero_uptime_mix_operator_rewarding_event(
interval_id: u32,
identity: IdentityKeyRef,
) -> Event {
Event::new(OPERATOR_REWARDING_EVENT_TYPE)
.add_attribute(INTERVAL_ID_KEY, interval_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(NO_REWARD_REASON_KEY, ZERO_UPTIME_VALUE)
}
pub fn new_mix_operator_rewarding_event(
interval_id: u32,
identity: IdentityKeyRef,
node_reward_result: NodeRewardResult,
operator_reward: Uint128,
delegation_rewards_distributed: Uint128,
further_delegations: bool,
) -> Event {
Event::new(OPERATOR_REWARDING_EVENT_TYPE)
.add_attribute(INTERVAL_ID_KEY, interval_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(
TOTAL_MIXNODE_REWARD_KEY,
node_reward_result.reward().to_string(),
)
.add_attribute(LAMBDA_KEY, node_reward_result.lambda().to_string())
.add_attribute(SIGMA_KEY, node_reward_result.sigma().to_string())
.add_attribute(OPERATOR_REWARD_KEY, operator_reward)
.add_attribute(
DISTRIBUTED_DELEGATION_REWARDS_KEY,
delegation_rewards_distributed,
)
.add_attribute(
FURTHER_DELEGATIONS_TO_REWARD_KEY,
further_delegations.to_string(),
)
}
pub fn new_mix_delegators_rewarding_event(
interval_id: u32,
identity: IdentityKeyRef,
delegation_rewards_distributed: Uint128,
further_delegations: bool,
) -> Event {
Event::new(MIX_DELEGATORS_REWARDING_EVENT_TYPE)
.add_attribute(INTERVAL_ID_KEY, interval_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(
DISTRIBUTED_DELEGATION_REWARDS_KEY,
delegation_rewards_distributed,
)
.add_attribute(
FURTHER_DELEGATIONS_TO_REWARD_KEY,
further_delegations.to_string(),
)
}
// note that when this event is emitted, we'll know the current block height
pub fn new_change_rewarded_set_event(
active_set_size: u32,
rewarded_set_size: u32,
nodes_in_rewarded_set: u32,
current_interval_id: u32,
) -> Event {
Event::new(CHANGE_REWARDED_SET_EVENT_TYPE)
.add_attribute(ACTIVE_SET_SIZE_KEY, active_set_size.to_string())
.add_attribute(REWARDED_SET_SIZE_KEY, rewarded_set_size.to_string())
.add_attribute(NODES_IN_REWARDED_SET_KEY, nodes_in_rewarded_set.to_string())
.add_attribute(CURRENT_INTERVAL_ID_KEY, current_interval_id.to_string())
}
pub fn new_advance_interval_event(interval: Interval) -> Event {
Event::new(ADVANCE_INTERVAL_EVENT_TYPE)
.add_attribute(NEW_CURRENT_INTERVAL_KEY, interval.to_string())
}
@@ -1,365 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::fmt::{Display, Formatter};
use std::time::Duration;
use time::OffsetDateTime;
// internally, since version 0.3.6, time uses deserialize_any for deserialization, which can't be handled
// by serde wasm. We could just downgrade to 0.3.5 and call it a day, but then it would break
// when we decided to upgrade it at some point in the future. And then it would have been more problematic
// to fix it, since the data would have already been stored inside the contract.
// Hence, an explicit workaround to use string representation of Rfc3339-formatted datetime.
pub(crate) mod string_rfc3339_offset_date_time {
use serde::de::Visitor;
use serde::ser::Error;
use serde::{Deserializer, Serialize, Serializer};
use std::fmt::Formatter;
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
struct Rfc3339OffsetDateTimeVisitor;
impl<'de> Visitor<'de> for Rfc3339OffsetDateTimeVisitor {
type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("an rfc3339 `OffsetDateTime`")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
OffsetDateTime::parse(value, &Rfc3339).map_err(E::custom)
}
}
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(Rfc3339OffsetDateTimeVisitor)
}
pub(crate) fn serialize<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
datetime
.format(&Rfc3339)
.map_err(S::Error::custom)?
.serialize(serializer)
}
}
/// Representation of rewarding interval.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
pub struct Interval {
id: u32,
#[serde(with = "string_rfc3339_offset_date_time")]
start: OffsetDateTime,
length: Duration,
}
impl Interval {
/// Creates new interval instance.
pub const fn new(id: u32, start: OffsetDateTime, length: Duration) -> Self {
Interval { id, start, length }
}
/// Returns the next interval.
#[must_use]
pub fn next_interval(&self) -> Self {
Interval {
id: self.id + 1,
start: self.end(),
length: self.length,
}
}
/// Returns the last interval.
pub fn previous_interval(&self) -> Option<Self> {
if self.id > 0 {
Some(Interval {
id: self.id - 1,
start: self.start - self.length,
length: self.length,
})
} else {
None
}
}
/// Determines whether the provided datetime is contained within the interval
///
/// # Arguments
///
/// * `datetime`: specified datetime
pub fn contains(&self, datetime: OffsetDateTime) -> bool {
self.start <= datetime && datetime <= self.end()
}
/// Determines whether the provided unix timestamp is contained within the interval
///
/// # Arguments
///
/// * `timestamp`: specified timestamp
pub fn contains_timestamp(&self, timestamp: i64) -> bool {
self.start_unix_timestamp() <= timestamp && timestamp <= self.end_unix_timestamp()
}
/// Returns new instance of [Interval] such that the provided datetime would be within
/// its duration.
///
/// # Arguments
///
/// * `now`: current datetime
pub fn current(&self, now: OffsetDateTime) -> Option<Self> {
let mut candidate = *self;
if now > self.start {
loop {
if candidate.contains(now) {
return Some(candidate);
}
candidate = candidate.next_interval();
}
} else {
loop {
if candidate.contains(now) {
return Some(candidate);
}
candidate = candidate.previous_interval()?;
}
}
}
/// Returns new instance of [Interval] such that the provided unix timestamp would be within
/// its duration.
///
/// # Arguments
///
/// * `now_unix`: current unix time
pub fn current_with_timestamp(&self, now_unix: i64) -> Option<Self> {
let mut candidate = *self;
if now_unix > self.start_unix_timestamp() {
loop {
if candidate.contains_timestamp(now_unix) {
return Some(candidate);
}
candidate = candidate.next_interval();
}
} else {
loop {
if candidate.contains_timestamp(now_unix) {
return Some(candidate);
}
candidate = candidate.previous_interval()?;
}
}
}
/// Checks whether this interval has already finished
///
/// # Arguments
///
/// * `now`: current datetime
pub fn has_elapsed(&self, now: OffsetDateTime) -> bool {
self.end() < now
}
/// Returns id of this interval
pub const fn id(&self) -> u32 {
self.id
}
/// Determines amount of time left until this interval finishes.
///
/// # Arguments
///
/// * `now`: current datetime
pub fn until_end(&self, now: OffsetDateTime) -> Option<Duration> {
let remaining = self.end() - now;
if remaining.is_negative() {
None
} else {
remaining.try_into().ok()
}
}
/// Returns the starting datetime of this interval.
pub const fn start(&self) -> OffsetDateTime {
self.start
}
/// Returns the length of this interval.
pub const fn length(&self) -> Duration {
self.length
}
/// Returns the ending datetime of this interval.
pub fn end(&self) -> OffsetDateTime {
self.start + self.length
}
/// Returns the unix timestamp of the start of this interval.
pub const fn start_unix_timestamp(&self) -> i64 {
self.start().unix_timestamp()
}
/// Returns the unix timestamp of the end of this interval.
pub fn end_unix_timestamp(&self) -> i64 {
self.end().unix_timestamp()
}
}
impl Display for Interval {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let length = self.length().as_secs();
let full_hours = length / 3600;
let rem = length % 3600;
write!(
f,
"Interval {}: {} - {} ({}h {}s)",
self.id,
self.start(),
self.end(),
full_hours,
rem
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn previous_interval() {
let interval = Interval {
id: 1,
start: time::macros::datetime!(2021-08-23 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
let expected = Interval {
id: 0,
start: time::macros::datetime!(2021-08-22 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
assert_eq!(expected, interval.previous_interval().unwrap());
let genesis_interval = Interval {
id: 0,
start: time::macros::datetime!(2021-08-23 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
assert!(genesis_interval.previous_interval().is_none());
}
#[test]
fn next_interval() {
let interval = Interval {
id: 0,
start: time::macros::datetime!(2021-08-23 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
let expected = Interval {
id: 1,
start: time::macros::datetime!(2021-08-24 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
assert_eq!(expected, interval.next_interval())
}
#[test]
fn checking_for_datetime_inclusion() {
let interval = Interval {
id: 100,
start: time::macros::datetime!(2021-08-23 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
// it must contain its own boundaries
assert!(interval.contains(interval.start));
assert!(interval.contains(interval.end()));
let in_the_midle = interval.start + Duration::from_secs(interval.length.as_secs() / 2);
assert!(interval.contains(in_the_midle));
assert!(!interval.contains(interval.next_interval().end()));
assert!(!interval.contains(interval.previous_interval().unwrap().start()));
}
#[test]
fn determining_current_interval() {
let first_interval = Interval {
id: 100,
start: time::macros::datetime!(2021-08-23 12:00 UTC),
length: Duration::from_secs(24 * 60 * 60),
};
// interval just before
let fake_now = first_interval.start - Duration::from_secs(123);
assert_eq!(
first_interval.previous_interval(),
first_interval.current(fake_now)
);
// this interval (start boundary)
assert_eq!(
first_interval,
first_interval.current(first_interval.start).unwrap()
);
// this interval (in the middle)
let fake_now = first_interval.start + Duration::from_secs(123);
assert_eq!(first_interval, first_interval.current(fake_now).unwrap());
// this interval (end boundary)
assert_eq!(
first_interval,
first_interval.current(first_interval.end()).unwrap()
);
// next interval
let fake_now = first_interval.end() + Duration::from_secs(123);
assert_eq!(
first_interval.next_interval(),
first_interval.current(fake_now).unwrap()
);
// few intervals in the past
let fake_now = first_interval.start()
- first_interval.length
- first_interval.length
- first_interval.length;
assert_eq!(
first_interval
.previous_interval()
.unwrap()
.previous_interval()
.unwrap()
.previous_interval()
.unwrap(),
first_interval.current(fake_now).unwrap()
);
// few intervals in the future
let fake_now = first_interval.end()
+ first_interval.length
+ first_interval.length
+ first_interval.length;
assert_eq!(
first_interval
.next_interval()
.next_interval()
.next_interval(),
first_interval.current(fake_now).unwrap()
);
}
}
@@ -1,9 +0,0 @@
[package]
name = "vesting-contract-common"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0-beta3"
@@ -1,133 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Addr, Coin, Event, Timestamp};
// event types
pub const WITHDRAW_EVENT_TYPE: &str = "vested_coins_withdraw";
pub const OWNERSHIP_TRANSFER_EVENT_TYPE: &str = "ownership_transfer";
pub const STAKING_ADDRESS_UPDATE_EVENT_TYPE: &str = "staking_address_update";
pub const NEW_PERIODIC_VESTING_ACCOUNT_EVENT_TYPE: &str = "new_periodic_vesting_account";
pub const VESTING_DELEGATION_EVENT_TYPE: &str = "vesting_delegation";
pub const VESTING_UNDELEGATION_EVENT_TYPE: &str = "vesting_undelegation";
pub const VESTING_GATEWAY_BONDING_EVENT_TYPE: &str = "vesting_gateway_bonding";
pub const VESTING_GATEWAY_UNBONDING_EVENT_TYPE: &str = "vesting_gateway_unbonding";
pub const VESTING_MIXNODE_BONDING_EVENT_TYPE: &str = "vesting_mixnode_bonding";
pub const VESTING_MIXNODE_UNBONDING_EVENT_TYPE: &str = "vesting_mixnode_unbonding";
pub const TRACK_MIXNODE_UNBOND_EVENT_TYPE: &str = "track_mixnode_unbond";
pub const TRACK_GATEWAY_UNBOND_EVENT_TYPE: &str = "track_gateway_unbond";
pub const TRACK_UNDELEGATION_EVENT_TYPE: &str = "track_undelegation";
// attributes that are used in multiple places
pub const OWNER_KEY: &str = "owner";
pub const AMOUNT_KEY: &str = "amount";
// event-specific attributes
// withdraw
pub const REMAINING_SPENDABLE_KEY: &str = "remaining_spendable";
// ownership transfer
pub const FROM_ACCOUNT_KEY: &str = "from";
pub const TO_ACCOUNT_KEY: &str = "to";
pub const NO_VALUE_VALUE: &str = "none";
// new vesting account
pub const START_TIME_KEY: &str = "start_time";
pub const STAKING_ADDRESS_KEY: &str = "staking_address";
// OPEN QUESTION: would it make sense to also emit amount of vesting/locked coins here?
// however, then it would require additional storage reads.
pub fn new_vested_coins_withdraw_event(
address: &Addr,
amount: &Coin,
remaining_spendable: &Coin,
) -> Event {
Event::new(WITHDRAW_EVENT_TYPE)
.add_attribute(OWNER_KEY, address)
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(REMAINING_SPENDABLE_KEY, remaining_spendable.to_string())
}
pub fn new_ownership_transfer_event(from: &Addr, to: &Addr) -> Event {
Event::new(OWNERSHIP_TRANSFER_EVENT_TYPE)
.add_attribute(FROM_ACCOUNT_KEY, from)
.add_attribute(TO_ACCOUNT_KEY, to)
}
pub fn new_staking_address_update_event(from: &Option<Addr>, to: &Option<Addr>) -> Event {
let mut event = Event::new(OWNERSHIP_TRANSFER_EVENT_TYPE);
if let Some(from) = from {
event = event.add_attribute(FROM_ACCOUNT_KEY, from)
} else {
event = event.add_attribute(FROM_ACCOUNT_KEY, NO_VALUE_VALUE);
}
if let Some(to) = to {
event = event.add_attribute(TO_ACCOUNT_KEY, to)
} else {
event = event.add_attribute(TO_ACCOUNT_KEY, NO_VALUE_VALUE);
}
event
}
pub fn new_periodic_vesting_account_event(
owner_address: &Addr,
amount: &Coin,
staking_address: &Option<Addr>,
start_time: Timestamp,
) -> Event {
let mut event = Event::new(NEW_PERIODIC_VESTING_ACCOUNT_EVENT_TYPE)
.add_attribute(OWNER_KEY, owner_address)
.add_attribute(AMOUNT_KEY, amount.to_string());
if let Some(staking_address) = staking_address {
event = event.add_attribute(STAKING_ADDRESS_KEY, staking_address);
}
event.add_attribute(START_TIME_KEY, start_time.to_string())
}
// In most cases the events are rather barebone as there's no point in attaching
// bunch of data to them as it would be redundant. It is because in most cases when the event is emitted
// a call to the mixnet contract is made that throws another event with relevant attributes already attached.
pub fn new_vesting_gateway_bonding_event() -> Event {
Event::new(VESTING_GATEWAY_BONDING_EVENT_TYPE)
}
pub fn new_vesting_gateway_unbonding_event() -> Event {
Event::new(VESTING_GATEWAY_UNBONDING_EVENT_TYPE)
}
pub fn new_vesting_mixnode_bonding_event() -> Event {
Event::new(VESTING_MIXNODE_BONDING_EVENT_TYPE)
}
pub fn new_vesting_mixnode_unbonding_event() -> Event {
Event::new(VESTING_MIXNODE_UNBONDING_EVENT_TYPE)
}
pub fn new_vesting_delegation_event() -> Event {
Event::new(VESTING_DELEGATION_EVENT_TYPE)
}
pub fn new_vesting_undelegation_event() -> Event {
Event::new(VESTING_UNDELEGATION_EVENT_TYPE)
}
pub fn new_track_mixnode_unbond_event() -> Event {
Event::new(TRACK_MIXNODE_UNBOND_EVENT_TYPE)
}
pub fn new_track_gateway_unbond_event() -> Event {
Event::new(TRACK_GATEWAY_UNBOND_EVENT_TYPE)
}
pub fn new_track_undelegation_event() -> Event {
Event::new(TRACK_UNDELEGATION_EVENT_TYPE)
}
@@ -1,4 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod events;
+1 -1
View File
@@ -27,7 +27,7 @@ pub struct BandwidthVoucherAttributes {
pub binding_number: PrivateAttribute, pub binding_number: PrivateAttribute,
// the value (e.g., bandwidth) encoded in this voucher // the value (e.g., bandwidth) encoded in this voucher
pub voucher_value: PublicAttribute, pub voucher_value: PublicAttribute,
// a field with public information, e.g., type of voucher, interval etc. // a field with public information, e.g., type of voucher, epoch etc.
pub voucher_info: PublicAttribute, pub voucher_info: PublicAttribute,
} }
+1 -3
View File
@@ -9,7 +9,7 @@ edition = "2018"
[dependencies] [dependencies]
aes = { version = "0.7.4", features = ["ctr"] } aes = { version = "0.7.4", features = ["ctr"] }
bs58 = "0.4.0" bs58 = "0.4.0"
blake3 = { version = "~1.2.0", features = ["traits-preview"] } blake3 = { version = "1.0.0", features = ["traits-preview"] }
digest = "0.9.0" digest = "0.9.0"
generic-array = "0.14" generic-array = "0.14"
hkdf = "0.11.0" hkdf = "0.11.0"
@@ -19,9 +19,7 @@ x25519-dalek = "1.1"
ed25519-dalek = "1.0" ed25519-dalek = "1.0"
log = "0.4" log = "0.4"
rand = { version = "0.7.3", features = ["wasm-bindgen"] } rand = { version = "0.7.3", features = ["wasm-bindgen"] }
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
# internal # internal
nymsphinx-types = { path = "../nymsphinx/types" } nymsphinx-types = { path = "../nymsphinx/types" }
pemstore = { path = "../../common/pemstore" } pemstore = { path = "../../common/pemstore" }
config = { path="../../common/config" }
@@ -189,13 +189,6 @@ impl PrivateKey {
let sig = expanded_secret_key.sign(message, &public_key.0); let sig = expanded_secret_key.sign(message, &public_key.0);
Signature(sig) Signature(sig)
} }
/// Signs text with the provided Ed25519 private key, returning a base58 signature
pub fn sign_text(&self, text: &str) -> String {
let signature_bytes = self.sign(text.as_ref()).to_bytes();
let signature = bs58::encode(signature_bytes).into_string();
signature
}
} }
impl PemStorableKey for PrivateKey { impl PemStorableKey for PrivateKey {
@@ -1,87 +0,0 @@
use config::defaults;
use subtle_encoding::bech32;
#[derive(Debug, Clone, PartialEq)]
pub enum Bech32Error {
DecodeFailed(String),
WrongPrefix(String),
}
/// Try to decode the address (to make sure it's a valid bech32 encoding)
pub fn try_bech32_decode(address: &str) -> Result<String, Bech32Error> {
match bech32::decode(address) {
Err(e) => Err(Bech32Error::DecodeFailed(e.to_string())),
Ok((prefix, _)) => Ok(prefix),
}
}
pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
let prefix = try_bech32_decode(address)?;
if prefix == defaults::BECH32_PREFIX {
Ok(())
} else {
Err(Bech32Error::WrongPrefix(format!(
"your bech32 address prefix should be {}, not {}",
defaults::BECH32_PREFIX,
prefix
)))
}
}
#[cfg(test)]
mod tests {
use super::*;
mod decoding_bech32_addresses {
use super::*;
#[test]
fn total_crap_fails() {
let res = try_bech32_decode("crap");
assert_eq!(
Err(Bech32Error::DecodeFailed("bad encoding".to_string())),
res
);
}
#[test]
fn bad_checksum_fails() {
let chopped_address = "punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu"; // this has the final "0" chopped off
let res = try_bech32_decode(chopped_address);
assert_eq!(
Err(Bech32Error::DecodeFailed("checksum mismatch".to_string())),
res
);
}
#[test]
fn good_address_returns_prefix() {
let prefix = try_bech32_decode("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0");
assert_eq!(Ok("punk".to_string()), prefix);
}
}
#[cfg(test)]
mod ensuring_correct_bech32_prefix {
use super::*;
#[test]
fn wrong_prefix_fails() {
assert_eq!(
Err(Bech32Error::WrongPrefix(
"your bech32 address prefix should be nymt, not punk".to_string()
)),
validate_bech32_prefix("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0")
)
}
#[test]
fn correct_prefix_works() {
assert_eq!(
Ok(()),
validate_bech32_prefix("nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9")
)
}
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ where
let hkdf = Hkdf::<D>::new(salt, ikm); let hkdf = Hkdf::<D>::new(salt, ikm);
let mut okm = vec![0u8; okm_length]; let mut okm = vec![0u8; okm_length];
hkdf.expand(info.unwrap_or(&[]), &mut okm)?; hkdf.expand(info.unwrap_or_else(|| &[]), &mut okm)?;
Ok(okm) Ok(okm)
} }
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
pub mod asymmetric; pub mod asymmetric;
pub mod bech32_address_validation;
pub mod crypto_hash; pub mod crypto_hash;
pub mod hkdf; pub mod hkdf;
pub mod hmac; pub mod hmac;
@@ -1,5 +1,5 @@
[package] [package]
name = "bandwidth-claim-contract" name = "erc20-bridge-contract"
version = "0.1.0" version = "0.1.0"
edition = "2018" edition = "2018"
@@ -1,5 +1,5 @@
[package] [package]
name = "mixnet-contract-common" name = "mixnet-contract"
version = "0.1.0" version = "0.1.0"
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2018" edition = "2018"
@@ -7,24 +7,17 @@ edition = "2018"
# 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-beta2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1" serde_repr = "0.1"
schemars = "0.8" schemars = "0.8"
ts-rs = { version = "5.1", optional = true } ts-rs = { version = "5.1", optional = true }
thiserror = "1.0" thiserror = "1.0"
network-defaults = { path = "../../network-defaults" } network-defaults = { path = "../network-defaults" }
fixed = { version = "1.1", features = ["serde"] } fixed = { version = "1.1", features = ["serde"] }
az = "1.1" az = "1.1"
log = "0.4.14" log = "0.4.14"
time = { version = "0.3.6", features = ["parsing", "formatting"] }
contracts-common = { path = "../contracts-common" }
[dev-dependencies]
time = { version = "0.3.5", features = ["serde", "macros"] }
[features] [features]
default = [] default = []
@@ -3,9 +3,7 @@
mod delegation; mod delegation;
pub mod error; pub mod error;
pub mod events;
mod gateway; mod gateway;
mod interval;
pub mod mixnode; pub mod mixnode;
mod msg; mod msg;
mod types; mod types;
@@ -18,9 +16,6 @@ pub use delegation::{
PagedMixDelegationsResponse, PagedMixDelegationsResponse,
}; };
pub use gateway::{Gateway, GatewayBond, GatewayOwnershipResponse, PagedGatewayResponse}; pub use gateway::{Gateway, GatewayBond, GatewayOwnershipResponse, PagedGatewayResponse};
pub use interval::Interval; pub use mixnode::{Layer, MixNode, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse};
pub use mixnode::{
Layer, MixNode, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse, RewardedSetNodeStatus,
};
pub use msg::*; pub use msg::*;
pub use types::*; pub use types::*;
@@ -5,7 +5,7 @@ use crate::{IdentityKey, SphinxKey};
use az::CheckedCast; use az::CheckedCast;
use cosmwasm_std::{coin, Addr, Coin, Uint128}; use cosmwasm_std::{coin, Addr, Coin, Uint128};
use log::error; use log::error;
use network_defaults::DEFAULT_OPERATOR_INTERVAL_COST; use network_defaults::DEFAULT_OPERATOR_EPOCH_COST;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
@@ -18,19 +18,6 @@ fixed::const_fixed_from_int! {
const ONE: U128 = 1; const ONE: U128 = 1;
} }
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
pub enum RewardedSetNodeStatus {
Active,
Standby,
}
impl RewardedSetNodeStatus {
pub fn is_active(&self) -> bool {
matches!(self, RewardedSetNodeStatus::Active)
}
}
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)] #[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
pub struct MixNode { pub struct MixNode {
@@ -66,16 +53,6 @@ pub enum Layer {
Three = 3, Three = 3,
} }
impl From<Layer> for String {
fn from(layer: Layer) -> Self {
if layer == Layer::Gateway {
"gateway".to_string()
} else {
(layer as u8).to_string()
}
}
}
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)] #[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
pub struct NodeRewardParams { pub struct NodeRewardParams {
period_reward_pool: Uint128, period_reward_pool: Uint128,
@@ -146,7 +123,7 @@ impl NodeRewardParams {
} }
pub fn operator_cost(&self) -> U128 { pub fn operator_cost(&self) -> U128 {
U128::from_num(self.uptime.u128() / 100u128 * DEFAULT_OPERATOR_INTERVAL_COST as u128) U128::from_num(self.uptime.u128() / 100u128 * DEFAULT_OPERATOR_EPOCH_COST as u128)
} }
pub fn set_reward_blockstamp(&mut self, blockstamp: u64) { pub fn set_reward_blockstamp(&mut self, blockstamp: u64) {
@@ -266,7 +243,7 @@ impl DelegatorRewardParams {
} }
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug)]
pub struct NodeRewardResult { pub struct NodeRewardResult {
reward: U128, reward: U128,
lambda: U128, lambda: U128,
@@ -338,7 +315,7 @@ impl MixNodeBond {
&self.mix_node &self.mix_node
} }
pub fn total_bond(&self) -> Option<u128> { pub fn total_stake(&self) -> Option<u128> {
if self.pledge_amount.denom != self.total_delegation.denom { if self.pledge_amount.denom != self.total_delegation.denom {
None None
} else { } else {
@@ -350,11 +327,6 @@ impl MixNodeBond {
self.total_delegation.clone() self.total_delegation.clone()
} }
pub fn stake_saturation(&self, circulating_supply: u128, rewarded_set_size: u32) -> U128 {
self.total_bond_to_circulating_supply(circulating_supply)
* U128::from_num(rewarded_set_size)
}
pub fn pledge_to_circulating_supply(&self, circulating_supply: u128) -> U128 { pub fn pledge_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
U128::from_num(self.pledge_amount().amount.u128()) / U128::from_num(circulating_supply) U128::from_num(self.pledge_amount().amount.u128()) / U128::from_num(circulating_supply)
} }
@@ -20,9 +20,6 @@ pub enum ExecuteMsg {
owner_signature: String, owner_signature: String,
}, },
UnbondMixnode {}, UnbondMixnode {},
UpdateMixnodeConfig {
profit_margin_percent: u8,
},
BondGateway { BondGateway {
gateway: Gateway, gateway: Gateway,
owner_signature: String, owner_signature: String,
@@ -38,18 +35,28 @@ pub enum ExecuteMsg {
mix_identity: IdentityKey, mix_identity: IdentityKey,
}, },
BeginMixnodeRewarding {
// nonce of the current rewarding interval
rewarding_interval_nonce: u32,
},
FinishMixnodeRewarding {
// nonce of the current rewarding interval
rewarding_interval_nonce: u32,
},
RewardMixnode { RewardMixnode {
identity: IdentityKey, identity: IdentityKey,
// percentage value in range 0-100 // percentage value in range 0-100
params: NodeRewardParams, params: NodeRewardParams,
// id of the current rewarding interval // nonce of the current rewarding interval
interval_id: u32, rewarding_interval_nonce: u32,
}, },
RewardNextMixDelegators { RewardNextMixDelegators {
mix_identity: IdentityKey, mix_identity: IdentityKey,
// id of the current rewarding interval // nonce of the current rewarding interval
interval_id: u32, rewarding_interval_nonce: u32,
}, },
DelegateToMixnodeOnBehalf { DelegateToMixnodeOnBehalf {
mix_identity: IdentityKey, mix_identity: IdentityKey,
@@ -75,11 +82,6 @@ pub enum ExecuteMsg {
UnbondGatewayOnBehalf { UnbondGatewayOnBehalf {
owner: String, owner: String,
}, },
WriteRewardedSet {
rewarded_set: Vec<IdentityKey>,
expected_active_set_size: u32,
},
AdvanceCurrentInterval {},
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -101,6 +103,7 @@ pub enum QueryMsg {
address: String, address: String,
}, },
StateParams {}, StateParams {},
CurrentRewardingInterval {},
// gets all [paged] delegations in the entire network // gets all [paged] delegations in the entire network
// TODO: do we even want that? // TODO: do we even want that?
GetAllNetworkDelegations { GetAllNetworkDelegations {
@@ -131,25 +134,12 @@ pub enum QueryMsg {
LayerDistribution {}, LayerDistribution {},
GetRewardPool {}, GetRewardPool {},
GetCirculatingSupply {}, GetCirculatingSupply {},
GetIntervalRewardPercent {}, GetEpochRewardPercent {},
GetSybilResistancePercent {}, GetSybilResistancePercent {},
GetActiveSetWorkFactor {},
GetRewardingStatus { GetRewardingStatus {
mix_identity: IdentityKey, mix_identity: IdentityKey,
interval_id: u32, rewarding_interval_nonce: u32,
}, },
GetRewardedSet {
height: Option<u64>,
start_after: Option<IdentityKey>,
limit: Option<u32>,
},
GetRewardedSetHeightsForInterval {
interval_id: u32,
},
GetRewardedSetUpdateDetails {},
GetCurrentRewardedSetHeight {},
GetCurrentInterval {},
GetRewardedSetRefreshBlocks {},
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::mixnode::DelegatorRewardParams; use crate::mixnode::DelegatorRewardParams;
use crate::{Layer, RewardedSetNodeStatus}; use crate::Layer;
use cosmwasm_std::{Addr, Uint128}; use cosmwasm_std::{Addr, Uint128};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -27,12 +27,19 @@ impl LayerDistribution {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq)]
pub struct RewardingIntervalResponse {
pub current_rewarding_interval_starting_block: u64,
pub current_rewarding_interval_nonce: u32,
pub rewarding_in_progress: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct ContractStateParams { pub struct ContractStateParams {
// so currently interval_length is being unused and validator API performs rewarding // so currently epoch_length is being unused and validator API performs rewarding
// based on its own interval length config value. I guess that's fine for time being // based on its own epoch length config value. I guess that's fine for time being
// however, in the future, the contract constant should be controlling it instead. // however, in the future, the contract constant should be controlling it instead.
// pub interval_length: u32, // length of a rewarding interval/interval, expressed in hours // pub epoch_length: u32, // length of a rewarding epoch/interval, expressed in hours
pub minimum_mixnode_pledge: Uint128, // minimum amount a mixnode must pledge to get into the system pub minimum_mixnode_pledge: Uint128, // minimum amount a mixnode must pledge to get into the system
pub minimum_gateway_pledge: Uint128, // minimum amount a gateway must pledge to get into the system pub minimum_gateway_pledge: Uint128, // minimum amount a gateway must pledge to get into the system
@@ -43,6 +50,7 @@ pub struct ContractStateParams {
// subset of rewarded mixnodes that are actively receiving mix traffic // subset of rewarded mixnodes that are actively receiving mix traffic
// used to handle shorter-term (e.g. hourly) fluctuations of demand // used to handle shorter-term (e.g. hourly) fluctuations of demand
pub mixnode_active_set_size: u32, pub mixnode_active_set_size: u32,
pub active_set_work_factor: u8,
} }
impl Display for ContractStateParams { impl Display for ContractStateParams {
@@ -67,6 +75,11 @@ impl Display for ContractStateParams {
f, f,
"mixnode active set size: {}", "mixnode active set size: {}",
self.mixnode_active_set_size self.mixnode_active_set_size
)?;
write!(
f,
"mixnode active set work factor: {}",
self.active_set_work_factor
) )
} }
} }
@@ -123,23 +136,3 @@ pub struct MixnetContractVersion {
pub type IdentityKey = String; pub type IdentityKey = String;
pub type IdentityKeyRef<'a> = &'a str; pub type IdentityKeyRef<'a> = &'a str;
pub type SphinxKey = String; pub type SphinxKey = String;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct PagedRewardedSetResponse {
pub identities: Vec<(IdentityKey, RewardedSetNodeStatus)>,
pub start_next_after: Option<IdentityKey>,
pub at_height: u64,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct RewardedSetUpdateDetails {
pub refresh_rate_blocks: u64,
pub last_refreshed_block: u64,
pub current_height: u64,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct IntervalRewardedSetHeightsResponse {
pub interval_id: u32,
pub heights: Vec<u64>,
}
-1
View File
@@ -77,7 +77,6 @@ impl Config {
} }
} }
#[must_use]
pub struct ConfigBuilder(Config); pub struct ConfigBuilder(Config);
impl ConfigBuilder { impl ConfigBuilder {
+1 -1
View File
@@ -7,7 +7,7 @@ edition = "2018"
# 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]
cfg-if = "1.0.0"
hex-literal = "0.3.3" hex-literal = "0.3.3"
serde = {version = "1.0", features = ["derive"]} serde = {version = "1.0", features = ["derive"]}
url = "2.2" url = "2.2"
time = { version = "0.3", features = ["macros"] }
+2 -2
View File
@@ -3,8 +3,8 @@
fn main() { fn main() {
match option_env!("NETWORK") { match option_env!("NETWORK") {
Some("milhon") => println!("cargo:rustc-cfg=network=\"milhon\"",), None | Some("milhon") => println!("cargo:rustc-cfg=network=\"milhon\"",),
None | Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",), Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""), Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
_ => panic!("No such network"), _ => panic!("No such network"),
} }
-130
View File
@@ -1,130 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::{milhon, qa, sandbox, ValidatorDetails};
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum Network {
MILHON,
QA,
SANDBOX,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NetworkDetails {
bech32_prefix: String,
denom: String,
mixnet_contract_address: String,
vesting_contract_address: String,
bandwidth_claim_contract_address: String,
rewarding_validator_address: String,
validators: Vec<ValidatorDetails>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SupportedNetworks {
networks: HashMap<Network, NetworkDetails>,
}
impl SupportedNetworks {
pub fn new(support: Vec<Network>) -> Self {
let mut networks = HashMap::new();
for network in support {
match network {
Network::MILHON => networks.insert(
Network::MILHON,
NetworkDetails {
bech32_prefix: String::from(milhon::BECH32_PREFIX),
denom: String::from(milhon::DENOM),
mixnet_contract_address: String::from(milhon::MIXNET_CONTRACT_ADDRESS),
vesting_contract_address: String::from(milhon::VESTING_CONTRACT_ADDRESS),
bandwidth_claim_contract_address: String::from(
milhon::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
),
rewarding_validator_address: String::from(
milhon::REWARDING_VALIDATOR_ADDRESS,
),
validators: milhon::validators(),
},
),
Network::QA => networks.insert(
Network::QA,
NetworkDetails {
bech32_prefix: String::from(qa::BECH32_PREFIX),
denom: String::from(qa::DENOM),
mixnet_contract_address: String::from(qa::MIXNET_CONTRACT_ADDRESS),
vesting_contract_address: String::from(qa::VESTING_CONTRACT_ADDRESS),
bandwidth_claim_contract_address: String::from(
qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
),
rewarding_validator_address: String::from(qa::REWARDING_VALIDATOR_ADDRESS),
validators: qa::validators(),
},
),
Network::SANDBOX => networks.insert(
Network::SANDBOX,
NetworkDetails {
bech32_prefix: String::from(sandbox::BECH32_PREFIX),
denom: String::from(sandbox::DENOM),
mixnet_contract_address: String::from(sandbox::MIXNET_CONTRACT_ADDRESS),
vesting_contract_address: String::from(sandbox::VESTING_CONTRACT_ADDRESS),
bandwidth_claim_contract_address: String::from(
sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
),
rewarding_validator_address: String::from(
sandbox::REWARDING_VALIDATOR_ADDRESS,
),
validators: sandbox::validators(),
},
),
};
}
SupportedNetworks { networks }
}
pub fn bech32_prefix(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.bech32_prefix.as_str())
}
pub fn denom(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.denom.as_str())
}
pub fn mixnet_contract_address(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.mixnet_contract_address.as_str())
}
pub fn vesting_contract_address(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.vesting_contract_address.as_str())
}
pub fn bandwidth_claim_contract_address(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.bandwidth_claim_contract_address.as_str())
}
pub fn rewarding_validator_address(&self, network: Network) -> Option<&str> {
self.networks
.get(&network)
.map(|network_details| network_details.rewarding_validator_address.as_str())
}
pub fn validators(&self, network: Network) -> Option<&Vec<ValidatorDetails>> {
self.networks
.get(&network)
.map(|network_details| &network_details.validators)
}
}
+33 -65
View File
@@ -1,65 +1,20 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net> // Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use time::OffsetDateTime;
use url::Url; use url::Url;
pub mod all;
pub mod eth_contract; pub mod eth_contract;
mod milhon; #[cfg(network = "milhon")]
mod qa; pub mod milhon;
mod sandbox; #[cfg(network = "sandbox")]
pub mod sandbox;
cfg_if::cfg_if! { #[cfg(network = "milhon")]
if #[cfg(network = "milhon")] { pub use milhon::*;
pub const BECH32_PREFIX: &str = milhon::BECH32_PREFIX; #[cfg(network = "sandbox")]
pub const DENOM: &str = milhon::DENOM; pub use sandbox::*;
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = milhon::MIXNET_CONTRACT_ADDRESS;
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = milhon::VESTING_CONTRACT_ADDRESS;
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = milhon::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
pub const DEFAULT_REWARDING_VALIDATOR_ADDRESS: &str = milhon::REWARDING_VALIDATOR_ADDRESS;
pub fn default_validators() -> Vec<ValidatorDetails> {
milhon::validators()
}
pub fn default_network() -> all::Network {
all::Network::MILHON
}
} else if #[cfg(network = "qa")] {
pub const BECH32_PREFIX: &str = qa::BECH32_PREFIX;
pub const DENOM: &str = qa::DENOM;
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = qa::MIXNET_CONTRACT_ADDRESS;
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = qa::VESTING_CONTRACT_ADDRESS;
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
pub const DEFAULT_REWARDING_VALIDATOR: &str = qa::REWARDING_VALIDATOR_ADDRESS;
pub fn default_validators() -> Vec<ValidatorDetails> {
qa::validators()
}
pub fn default_network() -> all::Network {
all::Network::QA
}
} else if #[cfg(network = "sandbox")] {
pub const BECH32_PREFIX: &str = sandbox::BECH32_PREFIX;
pub const DENOM: &str = sandbox::DENOM;
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = sandbox::MIXNET_CONTRACT_ADDRESS;
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = sandbox::VESTING_CONTRACT_ADDRESS;
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
pub const DEFAULT_REWARDING_VALIDATOR: &str = sandbox::REWARDING_VALIDATOR_ADDRESS;
pub fn default_validators() -> Vec<ValidatorDetails> {
sandbox::validators()
}
pub fn default_network() -> all::Network {
all::Network::SANDBOX
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ValidatorDetails { pub struct ValidatorDetails {
@@ -92,6 +47,25 @@ impl ValidatorDetails {
} }
} }
#[cfg(network = "milhon")]
pub fn default_validators() -> Vec<ValidatorDetails> {
vec![
ValidatorDetails::new(
"https://testnet-milhon-validator1.nymtech.net",
Some("https://testnet-milhon-validator1.nymtech.net/api"),
),
ValidatorDetails::new("https://testnet-milhon-validator2.nymtech.net", None),
]
}
#[cfg(network = "sandbox")]
pub fn default_validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://sandbox-validator.nymtech.net",
Some("https://sandbox-validator.nymtech.net/api"),
)]
}
pub fn default_nymd_endpoints() -> Vec<Url> { pub fn default_nymd_endpoints() -> Vec<Url> {
default_validators() default_validators()
.iter() .iter()
@@ -106,13 +80,6 @@ pub fn default_api_endpoints() -> Vec<Url> {
.collect() .collect()
} }
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
// Name of the event triggered by the eth contract. If the event name is changed,
// this would also need to be changed; It is currently tested against the json abi
pub const ETH_EVENT_NAME: &str = "Burned";
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
// Ethereum constants used for token bridge // Ethereum constants used for token bridge
/// How much bandwidth (in bytes) one token can buy /// How much bandwidth (in bytes) one token can buy
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024; const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
@@ -150,9 +117,10 @@ pub const DEFAULT_VALIDATOR_API_PORT: u16 = 8080;
pub const VALIDATOR_API_VERSION: &str = "v1"; pub const VALIDATOR_API_VERSION: &str = "v1";
// REWARDING // REWARDING
pub const DEFAULT_FIRST_EPOCH_START: OffsetDateTime = time::macros::datetime!(2021-08-23 12:00 UTC);
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate interval costs to Nyms. We'll also assume a cost of 40$ per interval(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60 * 30); // 30 days
pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 40_000_000; // 40$/(30 days) at 1 Nym == 1$ /// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate epoch costs to Nyms. We'll also assume a cost of 40$ per epoch(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
pub const DEFAULT_OPERATOR_EPOCH_COST: u64 = 40_000_000; // 40$/(30 days) at 1 Nym == 1$
// TODO: is there a way to get this from the chain // TODO: is there a way to get this from the chain
pub const TOTAL_SUPPLY: u128 = 1_000_000_000_000_000; pub const TOTAL_SUPPLY: u128 = 1_000_000_000_000_000;
+12 -18
View File
@@ -1,23 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::ValidatorDetails; pub const BECH32_PREFIX: &str = "punk";
pub const DENOM: &str = "upunk";
pub(crate) const BECH32_PREFIX: &str = "punk"; pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
pub(crate) const DENOM: &str = "upunk"; pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "";
pub const COSMOS_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen"; // Name of the event triggered by the eth contract. If the event name is changed,
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = ""; // this would also need to be changed; It is currently tested against the json abi
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = pub const ETH_EVENT_NAME: &str = "Burned";
"punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82"; pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![
ValidatorDetails::new(
"https://testnet-milhon-validator1.nymtech.net",
Some("https://testnet-milhon-validator1.nymtech.net/api"),
),
ValidatorDetails::new("https://testnet-milhon-validator2.nymtech.net", None),
]
}
-20
View File
@@ -1,20 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ValidatorDetails;
pub(crate) const BECH32_PREFIX: &str = "nymt";
pub(crate) const DENOM: &str = "unymt";
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt14hj2tavq8fpesdwxxcu44rty3hh90vhuysqrsr";
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1dn52nx8wv9wkqmrvj6tcmdzh4es6jt8tr7f6j9";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://qa-validator.nymtech.net",
Some("https://qa-validator.nymtech.net/api"),
)]
}
+12 -15
View File
@@ -1,20 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::ValidatorDetails; pub const BECH32_PREFIX: &str = "nymt";
pub const DENOM: &str = "unymt";
pub(crate) const BECH32_PREFIX: &str = "nymt"; pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "nymt14hj2tavq8fpesdwxxcu44rty3hh90vhuysqrsr";
pub(crate) const DENOM: &str = "unymt"; pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
pub const COSMOS_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j"; // Name of the event triggered by the eth contract. If the event name is changed,
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s"; // this would also need to be changed; It is currently tested against the json abi
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = pub const ETH_EVENT_NAME: &str = "Burned";
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv"; pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
"https://sandbox-validator.nymtech.net",
Some("https://sandbox-validator.nymtech.net/api"),
)]
}
+1 -1
View File
@@ -25,7 +25,7 @@ crypto = { path = "../crypto" }
topology = { path = "../topology" } topology = { path = "../topology" }
[dev-dependencies] [dev-dependencies]
mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" } mixnet-contract = { path = "../mixnet-contract" }
# do not include this when compiling into wasm as it somehow when combined together with reqwest, it will require # do not include this when compiling into wasm as it somehow when combined together with reqwest, it will require
# net2 via tokio-util -> tokio -> mio -> net2 # net2 via tokio-util -> tokio -> mio -> net2
+7 -2
View File
@@ -54,7 +54,6 @@ impl From<NymTopologyError> for PreparationError {
/// an optional reply-SURB, padding it to appropriate length, encrypting its content, /// an optional reply-SURB, padding it to appropriate length, encrypting its content,
/// and chunking into appropriate size [`Fragment`]s. /// and chunking into appropriate size [`Fragment`]s.
#[cfg_attr(not(target_arch = "wasm32"), derive(Clone))] #[cfg_attr(not(target_arch = "wasm32"), derive(Clone))]
#[must_use]
pub struct MessagePreparer<R: CryptoRng + Rng> { pub struct MessagePreparer<R: CryptoRng + Rng> {
/// Instance of a cryptographically secure random number generator. /// Instance of a cryptographically secure random number generator.
rng: R, rng: R,
@@ -387,7 +386,13 @@ where
// (note: surb_ack_bytes contains SURB_ACK_FIRST_HOP || SURB_ACK_DATA ) // (note: surb_ack_bytes contains SURB_ACK_FIRST_HOP || SURB_ACK_DATA )
let packet_payload: Vec<_> = surb_ack_bytes let packet_payload: Vec<_> = surb_ack_bytes
.into_iter() .into_iter()
.chain(reply_surb.encryption_key().compute_digest().iter().copied()) .chain(
reply_surb
.encryption_key()
.compute_digest()
.to_vec()
.into_iter(),
)
.chain(reply_content.into_iter()) .chain(reply_content.into_iter())
.collect(); .collect();
+1 -2
View File
@@ -58,7 +58,6 @@ impl MessageReceiver {
} }
/// Allows setting non-default number of expected mix hops in the network. /// Allows setting non-default number of expected mix hops in the network.
#[must_use]
pub fn with_mix_hops(mut self, hops: u8) -> Self { pub fn with_mix_hops(mut self, hops: u8) -> Self {
self.num_mix_hops = hops; self.num_mix_hops = hops;
self self
@@ -187,7 +186,7 @@ impl Default for MessageReceiver {
mod message_receiver { mod message_receiver {
use super::*; use super::*;
use crypto::asymmetric::identity; use crypto::asymmetric::identity;
use mixnet_contract_common::Layer; use mixnet_contract::Layer;
use nymsphinx_addressing::clients::Recipient; use nymsphinx_addressing::clients::Recipient;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use std::collections::HashMap; use std::collections::HashMap;
+1 -1
View File
@@ -13,7 +13,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] }
## internal ## internal
crypto = { path = "../crypto" } crypto = { path = "../crypto" }
mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" } mixnet-contract = { path = "../mixnet-contract" }
nymsphinx-addressing = { path = "../nymsphinx/addressing" } nymsphinx-addressing = { path = "../nymsphinx/addressing" }
nymsphinx-types = { path = "../nymsphinx/types" } nymsphinx-types = { path = "../nymsphinx/types" }
version-checker = { path = "../version-checker" } version-checker = { path = "../version-checker" }
-1
View File
@@ -9,7 +9,6 @@ pub trait Versioned: Clone {
} }
pub trait VersionFilterable<T> { pub trait VersionFilterable<T> {
#[must_use]
fn filter_by_version(&self, expected_version: &str) -> Self; fn filter_by_version(&self, expected_version: &str) -> Self;
} }
+1 -1
View File
@@ -3,7 +3,7 @@
use crate::{filter, NetworkAddress}; use crate::{filter, NetworkAddress};
use crypto::asymmetric::{encryption, identity}; use crypto::asymmetric::{encryption, identity};
use mixnet_contract_common::GatewayBond; use mixnet_contract::GatewayBond;
use nymsphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress}; use nymsphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
use nymsphinx_types::Node as SphinxNode; use nymsphinx_types::Node as SphinxNode;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
+2 -4
View File
@@ -3,7 +3,7 @@
use crate::filter::VersionFilterable; use crate::filter::VersionFilterable;
use log::warn; use log::warn;
use mixnet_contract_common::{GatewayBond, MixNodeBond}; use mixnet_contract::{GatewayBond, MixNodeBond};
use nymsphinx_addressing::nodes::NodeIdentity; use nymsphinx_addressing::nodes::NodeIdentity;
use nymsphinx_types::Node as SphinxNode; use nymsphinx_types::Node as SphinxNode;
use rand::Rng; use rand::Rng;
@@ -206,12 +206,10 @@ impl NymTopology {
true true
} }
#[must_use]
pub fn filter_system_version(&self, expected_version: &str) -> Self { pub fn filter_system_version(&self, expected_version: &str) -> Self {
self.filter_node_versions(expected_version, expected_version) self.filter_node_versions(expected_version, expected_version)
} }
#[must_use]
pub fn filter_node_versions( pub fn filter_node_versions(
&self, &self,
expected_mix_version: &str, expected_mix_version: &str,
@@ -274,7 +272,7 @@ mod converting_mixes_to_vec {
use crypto::asymmetric::{encryption, identity}; use crypto::asymmetric::{encryption, identity};
use super::*; use super::*;
use mixnet_contract_common::Layer; use mixnet_contract::Layer;
#[test] #[test]
fn returns_a_vec_with_hashmap_values() { fn returns_a_vec_with_hashmap_values() {
+1 -1
View File
@@ -3,7 +3,7 @@
use crate::{filter, NetworkAddress}; use crate::{filter, NetworkAddress};
use crypto::asymmetric::{encryption, identity}; use crypto::asymmetric::{encryption, identity};
use mixnet_contract_common::{Layer, MixNodeBond}; use mixnet_contract::{Layer, MixNodeBond};
use nymsphinx_addressing::nodes::NymNodeRoutingAddress; use nymsphinx_addressing::nodes::NymNodeRoutingAddress;
use nymsphinx_types::Node as SphinxNode; use nymsphinx_types::Node as SphinxNode;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
+120 -160
View File
@@ -17,9 +17,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.52" version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" checksum = "0a03e93e97a28fbc9f42fbc5ba0886a3c67eb637b476dbee711f80a6ffe8223d"
[[package]] [[package]]
name = "arrayref" name = "arrayref"
@@ -41,30 +41,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "az" name = "az"
version = "1.2.0" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4" checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "bandwidth-claim"
version = "0.1.0"
dependencies = [
"bandwidth-claim-contract",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "bandwidth-claim-contract"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]] [[package]]
name = "base64" name = "base64"
@@ -123,7 +102,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.4",
] ]
[[package]] [[package]]
@@ -143,9 +122,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.9.1" version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]] [[package]]
name = "byte-tools" name = "byte-tools"
@@ -155,9 +134,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.7.3" version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@@ -209,7 +188,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.4",
] ]
[[package]] [[package]]
@@ -237,17 +216,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "contracts-common" name = "cosmos_contract"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"config",
"cosmwasm-std", "cosmwasm-std",
"cosmwasm-storage",
"erc20-bridge-contract",
"schemars",
"serde",
"thiserror",
] ]
[[package]] [[package]]
name = "cosmwasm-crypto" name = "cosmwasm-crypto"
version = "1.0.0-beta3" version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a380b87642204557629c9b72988c47b55fbfe6d474960adba56b22331504956a" checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9"
dependencies = [ dependencies = [
"digest 0.9.0", "digest 0.9.0",
"ed25519-zebra", "ed25519-zebra",
@@ -258,18 +243,18 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-derive" name = "cosmwasm-derive"
version = "1.0.0-beta3" version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "866713b2fe13f23038c7d8824c3059d1f28dd94685fb406d1533c4eeeefeefae" checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2"
dependencies = [ dependencies = [
"syn", "syn",
] ]
[[package]] [[package]]
name = "cosmwasm-schema" name = "cosmwasm-schema"
version = "1.0.0-beta3" version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "818b928263c09a3269c2bed22494a62107a43ef87900e273af8ad2cb9f7e4440" checksum = "fe52b19d45fe3f8359db6cc24df44dbe05e5ae32539afc0f5b7f790a21aa6fd0"
dependencies = [ dependencies = [
"schemars", "schemars",
"serde_json", "serde_json",
@@ -277,9 +262,9 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-std" name = "cosmwasm-std"
version = "1.0.0-beta3" version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dbb9939b31441dfa9af3ec9740c8a24d585688401eff1b6b386abb7ad0d10a8" checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6"
dependencies = [ dependencies = [
"base64", "base64",
"cosmwasm-crypto", "cosmwasm-crypto",
@@ -293,9 +278,9 @@ dependencies = [
[[package]] [[package]]
name = "cosmwasm-storage" name = "cosmwasm-storage"
version = "1.0.0-beta3" version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4a4e55f0d64fed54cd2202301b8d466af8de044589247dabd77a4222f52f749" checksum = "cf3b4efe3b4f86df668520a02e9a29c23eea99b64dfcacb0e59b98346418af7f"
dependencies = [ dependencies = [
"cosmwasm-std", "cosmwasm-std",
"serde", "serde",
@@ -324,17 +309,15 @@ dependencies = [
"blake3", "blake3",
"bs58", "bs58",
"cipher", "cipher",
"config",
"digest 0.9.0", "digest 0.9.0",
"ed25519-dalek", "ed25519-dalek",
"generic-array 0.14.5", "generic-array 0.14.4",
"hkdf", "hkdf",
"hmac", "hmac",
"log", "log",
"nymsphinx-types", "nymsphinx-types",
"pemstore", "pemstore",
"rand", "rand",
"subtle-encoding",
"x25519-dalek", "x25519-dalek",
] ]
@@ -344,7 +327,7 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.4",
"rand_core 0.6.3", "rand_core 0.6.3",
"subtle 2.4.1", "subtle 2.4.1",
"zeroize", "zeroize",
@@ -366,7 +349,7 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.4",
"subtle 2.4.1", "subtle 2.4.1",
] ]
@@ -394,9 +377,9 @@ dependencies = [
[[package]] [[package]]
name = "cw-storage-plus" name = "cw-storage-plus"
version = "0.11.1" version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261" checksum = "d3b8b840947313c1a1cccf056836cd79a60b4526bdcd6582995be37dc97be4ae"
dependencies = [ dependencies = [
"cosmwasm-std", "cosmwasm-std",
"schemars", "schemars",
@@ -405,9 +388,9 @@ dependencies = [
[[package]] [[package]]
name = "der" name = "der"
version = "0.4.5" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
dependencies = [ dependencies = [
"const-oid", "const-oid",
] ]
@@ -427,7 +410,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array 0.14.4",
] ]
[[package]] [[package]]
@@ -493,7 +476,7 @@ checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
dependencies = [ dependencies = [
"crypto-bigint", "crypto-bigint",
"ff", "ff",
"generic-array 0.14.5", "generic-array 0.14.4",
"group", "group",
"pkcs8", "pkcs8",
"rand_core 0.6.3", "rand_core 0.6.3",
@@ -521,6 +504,14 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "erc20-bridge-contract"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]] [[package]]
name = "fake-simd" name = "fake-simd"
version = "0.1.2" version = "0.1.2"
@@ -539,9 +530,9 @@ dependencies = [
[[package]] [[package]]
name = "fixed" name = "fixed"
version = "1.11.0" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80a9a8cb2e34880a498f09367089339bda5e12d6f871640f947850f7113058c0" checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [ dependencies = [
"az", "az",
"bytemuck", "bytemuck",
@@ -571,9 +562,9 @@ dependencies = [
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.5" version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
@@ -605,9 +596,9 @@ dependencies = [
[[package]] [[package]]
name = "getset" name = "getset"
version = "0.1.2" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@@ -617,9 +608,9 @@ dependencies = [
[[package]] [[package]]
name = "git2" name = "git2"
version = "0.13.25" version = "0.13.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" checksum = "845e007a28f1fcac035715988a234e8ec5458fd825b20a20c7dec74237ef341f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"libc", "libc",
@@ -720,9 +711,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.1" version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
@@ -768,15 +759,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.112" version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]] [[package]]
name = "libgit2-sys" name = "libgit2-sys"
version = "0.12.26+1.3.0" version = "0.12.25+1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" checksum = "8f68169ef08d6519b2fe133ecc637408d933c0174b23b80bb2f79828966fbaab"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -838,32 +829,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]] [[package]]
name = "mixnet-contract" name = "mixnet-contract"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bs58",
"config",
"cosmwasm-schema",
"cosmwasm-std",
"cosmwasm-storage",
"crypto",
"cw-storage-plus",
"fixed",
"mixnet-contract-common",
"rand",
"rand_chacha",
"schemars",
"serde",
"thiserror",
"time 0.3.6",
"vergen",
"vesting-contract",
]
[[package]]
name = "mixnet-contract-common"
version = "0.1.0"
dependencies = [ dependencies = [
"az", "az",
"contracts-common",
"cosmwasm-std", "cosmwasm-std",
"fixed", "fixed",
"log", "log",
@@ -872,16 +839,37 @@ dependencies = [
"serde", "serde",
"serde_repr", "serde_repr",
"thiserror", "thiserror",
"time 0.3.6", ]
[[package]]
name = "mixnet-contracts"
version = "0.1.0"
dependencies = [
"bs58",
"config",
"cosmwasm-schema",
"cosmwasm-std",
"cosmwasm-storage",
"crypto",
"cw-storage-plus",
"fixed",
"mixnet-contract",
"rand",
"rand_chacha",
"schemars",
"serde",
"thiserror",
"vergen",
"vesting-contract",
] ]
[[package]] [[package]]
name = "network-defaults" name = "network-defaults"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cfg-if",
"hex-literal", "hex-literal",
"serde", "serde",
"time 0.3.5",
"url", "url",
] ]
@@ -905,15 +893,6 @@ dependencies = [
"libm", "libm",
] ]
[[package]]
name = "num_threads"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71a1eb3a36534514077c1e079ada2fb170ef30c47d203aa6916138cf882ecd52"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "nymsphinx-types" name = "nymsphinx-types"
version = "0.1.0" version = "0.1.0"
@@ -923,9 +902,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.9.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
@@ -1018,15 +997,15 @@ dependencies = [
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.24" version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.16" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
@@ -1054,9 +1033,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
@@ -1069,9 +1048,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.14" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -1162,21 +1141,21 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.6" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.9" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.8" version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3" checksum = "271ac0c667b8229adf70f0f957697c96fafd7486ab7481e15dc5e45e3e6a4368"
dependencies = [ dependencies = [
"dyn-clone", "dyn-clone",
"schemars_derive", "schemars_derive",
@@ -1186,9 +1165,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.8" version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b" checksum = "6ebda811090b257411540779860bc09bf321bc587f58d2c5864309d1566214e7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1204,27 +1183,27 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.133" version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde-json-wasm" name = "serde-json-wasm"
version = "0.3.2" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "042ac496d97e5885149d34139bad1d617192770d7eb8f1866da2317ff4501853" checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.133" version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1244,9 +1223,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.74" version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -1278,9 +1257,9 @@ dependencies = [
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.9" version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [ dependencies = [
"block-buffer 0.9.0", "block-buffer 0.9.0",
"cfg-if", "cfg-if",
@@ -1349,20 +1328,11 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "subtle-encoding"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945"
dependencies = [
"zeroize",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.85" version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1413,13 +1383,11 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.6" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d54b9298e05179c335de2b9645d061255bcd5155f843b3e328d2cfe0a5b413" checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
dependencies = [ dependencies = [
"itoa",
"libc", "libc",
"num_threads",
"time-macros", "time-macros",
] ]
@@ -1455,9 +1423,9 @@ dependencies = [
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.15.0" version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]] [[package]]
name = "ucd-trie" name = "ucd-trie"
@@ -1518,9 +1486,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "vergen" name = "vergen"
version = "5.1.17" version = "5.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cf88d94e969e7956d924ba70741316796177fa0c79a2c9f4ab04998d96e966e" checksum = "1d48696c0fbbdafd9553e14c4584b4b9583931e9474a3ae506f1872b890d0b47"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if", "cfg-if",
@@ -1535,9 +1503,9 @@ dependencies = [
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]] [[package]]
name = "vesting-contract" name = "vesting-contract"
@@ -1546,18 +1514,10 @@ dependencies = [
"config", "config",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"mixnet-contract-common", "mixnet-contract",
"schemars", "schemars",
"serde", "serde",
"thiserror", "thiserror",
"vesting-contract-common",
]
[[package]]
name = "vesting-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
] ]
[[package]] [[package]]
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["bandwidth-claim", "mixnet", "vesting"] members = ["erc20-bridge", "mixnet", "vesting"]
[profile.release] [profile.release]
opt-level = 3 opt-level = 3

Some files were not shown because too many files have changed in this diff Show More