Compare commits

...

22 Commits

Author SHA1 Message Date
Drazen Urch 465f184ad9 Milhon compat changes 2021-11-05 09:28:38 +01:00
durch 67edfdf1f3 [ci skip] Generate TS types 2021-11-03 13:20:47 +00:00
Drazen Urch 4aa12ecaab Simplify formula 2021-11-03 13:02:28 +01:00
Drazen Urch 4277605502 Cleanup, better test values 2021-11-03 12:18:23 +01:00
Drazen Urch 6aed23960c Address review comments 2021-11-03 11:26:48 +01:00
Drazen Urch 0f66be4c83 Fix test imports 2021-11-03 11:26:48 +01:00
Drazen Urch 42ac95b0c6 TODOs, add Justfile 2021-11-03 11:26:39 +01:00
Drazen Urch 6999cc89b7 Refactor rewarding and replace num crate 2021-11-03 11:26:24 +01:00
Drazen Urch 72bb5a239b Fix circulating supply query 2021-11-03 11:26:24 +01:00
Drazen Urch da34c2e50b Update tokenomics 2021-11-03 11:26:17 +01:00
Drazen Urch 0630c4c240 Bandwidth fix, reduce inflation pool size 2021-11-03 11:26:07 +01:00
Drazen Urch cf8758ab19 Add migration 2021-11-03 11:25:57 +01:00
Drazen Urch 94cdb996dc Fix performance calculation 2021-11-03 11:25:28 +01:00
Drazen Urch 32036e4fb7 No more floats
[ci skip] Generate TS types
2021-11-03 11:25:28 +01:00
Drazen Urch a4eb449391 Feature gate ts-rs in mixnet-contract 2021-11-03 11:24:27 +01:00
Drazen Urch 85f745fd14 Tests and refactoring for better testability 2021-11-03 11:24:12 +01:00
Drazen Urch c4bd5e04a5 Finalize implementation
Fix reciprocal

Fix, fix reciprocal

cargo fmt
2021-11-03 11:24:12 +01:00
Drazen Urch b47dad1b7d Tidy up ratio calcs a bit 2021-11-03 11:23:53 +01:00
Drazen Urch ef3cccfa8b Assume a bunch of stuff and implement operator reward 2021-11-03 11:23:53 +01:00
Drazen Urch 91836f6464 Fix formula discrepancy 2021-11-03 11:23:53 +01:00
Drazen Urch 5ba300c581 Implement core rewards distribution 2021-11-03 11:23:52 +01:00
Drazen Urch 22a4b03ce6 Initial analysis 2021-11-03 11:22:57 +01:00
32 changed files with 1154 additions and 190 deletions
+3
View File
@@ -30,3 +30,6 @@ validator-api/v4.json
validator-api/v6.json
**/node_modules
validator-api/keypair
contracts/mixnet/code_id
contracts/mixnet/Justfile
contracts/mixnet/Makefile
Generated
+35
View File
@@ -246,6 +246,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "backtrace"
version = "0.3.61"
@@ -444,6 +450,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -1675,6 +1687,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixed"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "flate2"
version = "1.0.22"
@@ -2300,6 +2324,12 @@ dependencies = [
"tracing",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "3.5.5"
@@ -3023,10 +3053,15 @@ dependencies = [
name = "mixnet-contract"
version = "0.1.0"
dependencies = [
"az",
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
"thiserror",
"ts-rs",
]
+1 -1
View File
@@ -62,4 +62,4 @@ default-members = [
"validator-api",
]
exclude = ["explorer", "contracts"]
exclude = ["explorer", "contracts", "tokenomics-py"]
@@ -518,8 +518,12 @@ impl GatewayClient {
return Err(GatewayClientError::NotAuthenticated);
}
#[cfg(feature = "coconut")]
if self.estimate_required_bandwidth(&packets) < self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth);
if self.bandwidth_remaining <= self.estimate_required_bandwidth(&packets) {
return Err(GatewayClientError::NotEnoughBandwidth((
line!(),
self.estimate_required_bandwidth(&packets),
self.bandwidth_remaining,
)));
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
@@ -587,7 +591,11 @@ impl GatewayClient {
}
#[cfg(feature = "coconut")]
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth);
return Err(GatewayClientError::NotEnoughBandwidth((
line!(),
(mix_packet.sphinx_packet().len() as i64),
self.bandwidth_remaining,
)));
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
@@ -626,7 +634,11 @@ impl GatewayClient {
}
#[cfg(feature = "coconut")]
if self.bandwidth_remaining <= 0 {
return Err(GatewayClientError::NotEnoughBandwidth);
return Err(GatewayClientError::NotEnoughBandwidth((
line!(),
0,
self.bandwidth_remaining,
)));
}
if self.connection.is_partially_delegated() {
return Ok(());
@@ -23,7 +23,7 @@ pub enum GatewayClientError {
MalformedResponse,
SerializeCredential,
NotAuthenticated,
NotEnoughBandwidth,
NotEnoughBandwidth((u32, i64, i64)),
UnexpectedResponse,
ConnectionInInvalidState,
RegistrationFailure(HandshakeError),
@@ -102,8 +102,12 @@ impl fmt::Display for GatewayClientError {
write!(f, "gateway returned an error response - {}", err)
}
GatewayClientError::UnexpectedResponse => write!(f, "received an unexpected response"),
GatewayClientError::NotEnoughBandwidth => {
write!(f, "client does not have enough bandwidth")
GatewayClientError::NotEnoughBandwidth((line_number, estimated, remaining)) => {
write!(
f,
"line: {} - client does not have enough bandwidth: estimated {}, remaining: {}",
line_number, estimated, remaining
)
}
GatewayClientError::SerializeCredential => {
write!(f, "credential could not be serialized")
@@ -119,7 +119,7 @@ impl PartiallyDelegated {
}
.is_err()
{
panic!("failed to send back `mixnet_receiver_future` result on the oneshot channel")
info!("failed to send back `mixnet_receiver_future` result on the oneshot channel")
}
};
@@ -182,6 +182,34 @@ impl<C> Client<C> {
Ok(self.nymd.get_state_params().await?)
}
pub async fn get_reward_pool(&self) -> Result<u128, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_reward_pool().await?.u128())
}
pub async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_circulating_supply().await?.u128())
}
pub async fn get_sybil_resistance_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_sybil_resistance_percent().await?)
}
pub async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_epoch_reward_percent().await?)
}
// basically handles paging for us
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
@@ -11,7 +11,7 @@ use crate::nymd::fee_helpers::Operation;
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClientUrl};
use cosmwasm_std::Coin;
use cosmwasm_std::{Coin, Uint128};
use mixnet_contract::{
Addr, Delegation, ExecuteMsg, Gateway, GatewayOwnershipResponse, IdentityKey,
LayerDistribution, MixNode, MixOwnershipResponse, PagedAllDelegationsResponse,
@@ -212,6 +212,46 @@ impl<C> NymdClient<C> {
.await
}
pub async fn get_reward_pool(&self) -> Result<Uint128, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetRewardPool {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_circulating_supply(&self) -> Result<Uint128, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetCirculatingSupply {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_sybil_resistance_percent(&self) -> Result<u8, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetSybilResistancePercent {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_epoch_reward_percent(&self) -> Result<u8, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetEpochRewardPercent {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
/// Checks whether there is a bonded mixnode associated with the provided client's address
pub async fn owns_mixnode(&self, address: &AccountId) -> Result<bool, NymdError>
where
+10 -2
View File
@@ -8,10 +8,18 @@ edition = "2018"
[dependencies]
# this branch is identical to 0.14.1 with addition of updated k256 dependency required to help poor cargo choose correct version
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256" }
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch = "0.14.1-updatedk256" }
#cosmwasm-std = { version = "0.14.1" }
serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
schemars = "0.8"
ts-rs = "3.0"
ts-rs = { version = "3.0", optional = true }
thiserror = "1.0"
network-defaults = { path = "../network-defaults" }
fixed = "1.1"
az = "1.1"
log = "0.4.14"
[features]
default = ["ts-rs"]
+9
View File
@@ -0,0 +1,9 @@
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum MixnetContractError {
#[error("Overflow Error")]
OverflowError(#[from] cosmwasm_std::OverflowError),
#[error("reward_blockstamp field not set, set_reward_blockstamp must be called before attempting to issue rewards")]
BlockstampNotSet,
}
+6 -2
View File
@@ -7,11 +7,11 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fmt::Display;
use ts_rs::TS;
use crate::current_block_height;
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema, TS)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
pub struct Gateway {
pub host: String,
pub mix_port: u16,
@@ -59,6 +59,10 @@ impl GatewayBond {
pub fn gateway(&self) -> &Gateway {
&self.gateway
}
pub fn total_delegation(&self) -> Coin {
self.total_delegation.clone()
}
}
impl PartialOrd for GatewayBond {
+2 -1
View File
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
mod delegation;
pub mod error;
mod gateway;
mod mixnode;
pub mod mixnode;
mod msg;
mod types;
+224 -3
View File
@@ -2,17 +2,22 @@
#![allow(clippy::field_reassign_with_default)]
use crate::{IdentityKey, SphinxKey};
use cosmwasm_std::{coin, Addr, Coin};
use az::CheckedCast;
use cosmwasm_std::{coin, Addr, Coin, Uint128};
use log::error;
use network_defaults::{DEFAULT_OPERATOR_EPOCH_COST, DEFAULT_PROFIT_MARGIN};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::cmp::Ordering;
use std::fmt::Display;
use ts_rs::TS;
use crate::current_block_height;
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema, TS)]
type U128 = fixed::types::U75F53; // u128 with 18 significant digits
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
pub struct MixNode {
pub host: String,
pub mix_port: u16,
@@ -35,6 +40,101 @@ pub enum Layer {
Three = 3,
}
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
pub struct NodeRewardParams {
period_reward_pool: Uint128,
k: Uint128,
total_epoch_uptime: Uint128,
#[serde(default = "current_block_height")]
reward_blockstamp: u64,
circulating_supply: Uint128,
uptime: Uint128,
sybil_resistance_percent: u8,
}
impl NodeRewardParams {
pub fn new(
period_reward_pool: u128,
k: u128,
total_epoch_uptime: u128,
reward_blockstamp: u64,
circulating_supply: u128,
uptime: u128,
sybil_resistance_percent: u8,
) -> NodeRewardParams {
NodeRewardParams {
period_reward_pool: Uint128(period_reward_pool),
k: Uint128(k),
total_epoch_uptime: Uint128(total_epoch_uptime),
reward_blockstamp,
circulating_supply: Uint128(circulating_supply),
uptime: Uint128(uptime),
sybil_resistance_percent,
}
}
pub fn performance(&self) -> U128 {
U128::from_num(self.uptime.u128()) / U128::from_num(100)
}
pub fn operator_cost(&self) -> U128 {
U128::from_num(self.uptime.u128() / 100u128 * DEFAULT_OPERATOR_EPOCH_COST as u128)
}
pub fn set_reward_blockstamp(&mut self, blockstamp: u64) {
self.reward_blockstamp = blockstamp;
}
pub fn period_reward_pool(&self) -> u128 {
self.period_reward_pool.u128()
}
pub fn k(&self) -> u128 {
self.k.u128()
}
pub fn circulating_supply(&self) -> u128 {
self.circulating_supply.u128()
}
pub fn reward_blockstamp(&self) -> u64 {
self.reward_blockstamp
}
pub fn uptime(&self) -> u128 {
self.uptime.u128()
}
pub fn one_over_k(&self) -> U128 {
U128::from_num(1) / U128::from_num(self.k.u128())
}
pub fn alpha(&self) -> U128 {
U128::from_num(self.sybil_resistance_percent) / U128::from_num(100)
}
}
#[derive(Debug)]
pub struct NodeRewardResult {
reward: U128,
lambda: U128,
sigma: U128,
}
impl NodeRewardResult {
pub fn reward(&self) -> U128 {
self.reward
}
pub fn lambda(&self) -> U128 {
self.lambda
}
pub fn sigma(&self) -> U128 {
self.sigma
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct MixNodeBond {
pub bond_amount: Coin,
@@ -44,6 +144,7 @@ pub struct MixNodeBond {
#[serde(default = "current_block_height")]
pub block_height: u64,
pub mix_node: MixNode,
pub profit_margin_percent: Option<u8>,
}
impl MixNodeBond {
@@ -53,6 +154,7 @@ impl MixNodeBond {
layer: Layer,
block_height: u64,
mix_node: MixNode,
profit_margin_percent: Option<u8>,
) -> Self {
MixNodeBond {
total_delegation: coin(0, &bond_amount.denom),
@@ -61,9 +163,14 @@ impl MixNodeBond {
layer,
block_height,
mix_node,
profit_margin_percent,
}
}
pub fn profit_margin(&self) -> U128 {
U128::from_num(self.profit_margin_percent.unwrap_or(DEFAULT_PROFIT_MARGIN)) / U128::from_num(100)
}
pub fn identity(&self) -> &String {
&self.mix_node.identity_key
}
@@ -79,6 +186,115 @@ impl MixNodeBond {
pub fn mix_node(&self) -> &MixNode {
&self.mix_node
}
pub fn total_delegation(&self) -> Coin {
self.total_delegation.clone()
}
pub fn bond_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
U128::from_num(self.bond_amount().amount.u128()) / U128::from_num(circulating_supply)
}
pub fn total_stake_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
U128::from_num(self.bond_amount().amount.u128() + self.total_delegation().amount.u128())
/ U128::from_num(circulating_supply)
}
pub fn lambda(&self, params: &NodeRewardParams) -> U128 {
// Ratio of a bond to the token circulating supply
let bond_to_circulating_supply_ratio =
self.bond_to_circulating_supply(params.circulating_supply());
bond_to_circulating_supply_ratio.min(params.one_over_k())
}
pub fn sigma(&self, params: &NodeRewardParams) -> U128 {
// Ratio of a delegation to the the token circulating supply
let total_stake_to_circulating_supply_ratio =
self.total_stake_to_circulating_supply(params.circulating_supply());
total_stake_to_circulating_supply_ratio.min(params.one_over_k())
}
pub fn reward(&self, params: &NodeRewardParams) -> NodeRewardResult {
// Assuming uniform work distribution across the network this is one_over_k * k
let omega_k = U128::from_num(1u128);
let lambda = self.lambda(params);
let sigma = self.sigma(params);
let reward = params.performance()
* params.period_reward_pool()
* (sigma * omega_k + params.alpha() * lambda * sigma * params.k())
/ (U128::from_num(1) + params.alpha());
NodeRewardResult {
reward,
lambda,
sigma,
}
}
pub fn node_profit(&self, params: &NodeRewardParams) -> U128 {
if self.reward(params).reward() < params.operator_cost() {
U128::from_num(0)
} else {
self.reward(params).reward() - params.operator_cost()
}
}
pub fn operator_reward(&self, params: &NodeRewardParams) -> u128 {
let reward = self.reward(params);
let profit = if reward.reward < params.operator_cost() {
U128::from_num(0)
} else {
reward.reward - params.operator_cost()
};
let operator_base_reward = reward.reward.min(params.operator_cost());
let operator_reward = (self.profit_margin()
+ (U128::from_num(1) - self.profit_margin()) * reward.lambda / reward.sigma)
* profit;
let reward = (operator_reward + operator_base_reward).max(U128::from_num(0));
if let Some(int_reward) = reward.checked_cast() {
int_reward
} else {
error!(
"Could not cast reward ({}) to u128, returning 0 - mixnode {}",
reward,
self.identity()
);
0u128
}
}
pub fn sigma_ratio(&self, params: &NodeRewardParams) -> U128 {
if self.total_stake_to_circulating_supply(params.circulating_supply()) < params.one_over_k()
{
self.total_stake_to_circulating_supply(params.circulating_supply())
} else {
params.one_over_k()
}
}
pub fn reward_delegation(&self, delegation_amount: Uint128, params: &NodeRewardParams) -> u128 {
let scaled_delegation_amount =
U128::from_num(delegation_amount.u128()) / U128::from_num(params.circulating_supply());
let delegator_reward = (U128::from_num(1) - self.profit_margin())
* scaled_delegation_amount / self.sigma(params)
* self.node_profit(params);
let reward = delegator_reward.max(U128::from_num(0));
if let Some(int_reward) = reward.checked_cast() {
int_reward
} else {
error!(
"Could not cast delegator reward ({}) to u128, returning 0 - mixnode {}",
reward,
self.identity()
);
0u128
}
}
}
impl PartialOrd for MixNodeBond {
@@ -210,6 +426,7 @@ mod tests {
layer: Layer::One,
block_height: 100,
mix_node: mixnode_fixture(),
profit_margin_percent: 10,
};
let mix2 = MixNodeBond {
@@ -219,6 +436,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: 10,
};
let mix3 = MixNodeBond {
@@ -228,6 +446,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: 10,
};
let mix4 = MixNodeBond {
@@ -237,6 +456,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: 10,
};
let mix5 = MixNodeBond {
@@ -246,6 +466,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: 10,
};
// summary:
+11
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::mixnode::NodeRewardParams;
use crate::StateParams;
use crate::{Gateway, IdentityKey, MixNode};
use cosmwasm_std::Addr;
@@ -45,6 +46,12 @@ pub enum ExecuteMsg {
uptime: u32,
},
RewardMixnodeV2 {
identity: IdentityKey,
// percentage value in range 0-100
params: NodeRewardParams,
},
RewardGateway {
identity: IdentityKey,
// percentage value in range 0-100
@@ -107,6 +114,10 @@ pub enum QueryMsg {
address: Addr,
},
LayerDistribution {},
GetRewardPool {},
GetCirculatingSupply {},
GetEpochRewardPercent {},
GetSybilResistancePercent {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
+8 -1
View File
@@ -93,4 +93,11 @@ pub const VALIDATOR_API_VERSION: &str = "v1";
// REWARDING
pub const DEFAULT_FIRST_EPOCH_START: OffsetDateTime = time::macros::datetime!(2021-08-23 12:00 UTC);
pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60); // 24h
pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60 * 30); // 30 days
/// 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
pub const TOTAL_SUPPLY: u128 = 1_000_000_000_000_000;
pub const DEFAULT_PROFIT_MARGIN: u8 = 10;
+1
View File
@@ -0,0 +1 @@
.envrc
+213 -93
View File
@@ -23,9 +23,9 @@ dependencies = [
[[package]]
name = "ast_node"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93f52ce8fac3d0e6720a92b0576d737c01b1b5db4dd786e962e5925f00bf755"
checksum = "e96d5444b02f3080edac8a144f6baf29b2fb6ff589ad4311559731a7c7529381"
dependencies = [
"darling",
"pmutil",
@@ -41,12 +41,24 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.7.3"
@@ -79,9 +91,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.7.1"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byte-tools"
@@ -89,6 +101,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -121,9 +139,9 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.6.0"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c32f031ea41b4291d695026c023b95d59db2d8a2c7640800ed56bc8f510f22"
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
[[package]]
name = "cosmwasm-crypto"
@@ -147,9 +165,9 @@ dependencies = [
[[package]]
name = "cosmwasm-schema"
version = "0.14.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6a9a6a4ca3b4d7b56f943312a65857cdfc84424f9c2773889f4cd17f36fba61"
checksum = "04159eec9b583671db7923ff2b979736dfb8f0152347cab9fd02373c22e1a870"
dependencies = [
"schemars",
"serde_json",
@@ -181,9 +199,9 @@ dependencies = [
[[package]]
name = "cpufeatures"
version = "0.1.4"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
@@ -196,9 +214,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-bigint"
version = "0.2.2"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32a398eb1ccfbe7e4f452bc749c44d38dd732e9a253f19da224c416f00ee7f4"
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
dependencies = [
"generic-array 0.14.4",
"rand_core 0.6.3",
@@ -218,9 +236,9 @@ dependencies = [
[[package]]
name = "curve25519-dalek"
version = "3.1.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3"
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [
"byteorder",
"digest 0.9.0",
@@ -266,9 +284,9 @@ dependencies = [
[[package]]
name = "der"
version = "0.4.0"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f215f706081a44cb702c71c39a52c05da637822e9c1645a50b7202689e982d"
checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
dependencies = [
"const-oid",
]
@@ -338,9 +356,9 @@ checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf"
[[package]]
name = "ecdsa"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713c32426287891008edb98f8b5c6abb2130aa043c93a818728fcda78606f274"
checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
dependencies = [
"der",
"elliptic-curve",
@@ -370,9 +388,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "elliptic-curve"
version = "0.10.4"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8"
checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
dependencies = [
"crypto-bigint",
"ff",
@@ -404,14 +422,26 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "ff"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63eec06c61e487eecf0f7e6e6372e596a81922c28d33e645d6983ca6493a1af0"
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
dependencies = [
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "fixed"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -501,6 +531,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "3.5.5"
@@ -564,6 +600,15 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "is-macro"
version = "0.1.9"
@@ -579,15 +624,15 @@ dependencies = [
[[package]]
name = "itoa"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "k256"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "008b0281ca8032567c9711cd48631781c15228301860a39b32deb28d63125e46"
checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
dependencies = [
"cfg-if 1.0.0",
"ecdsa",
@@ -603,9 +648,18 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.100"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
[[package]]
name = "lock_api"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
@@ -624,9 +678,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matches"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
@@ -638,10 +692,15 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
name = "mixnet-contract"
version = "0.1.0"
dependencies = [
"az",
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
"thiserror",
"ts-rs",
]
@@ -653,6 +712,7 @@ dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cosmwasm-storage",
"fixed",
"mixnet-contract",
"schemars",
"serde",
@@ -732,6 +792,31 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if 1.0.0",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -802,9 +887,9 @@ dependencies = [
[[package]]
name = "pkcs8"
version = "0.7.5"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbee84ed13e44dd82689fa18348a49934fa79cc774a344c42fc9b301c71b140a"
checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
dependencies = [
"der",
"spki",
@@ -823,9 +908,9 @@ dependencies = [
[[package]]
name = "ppv-lite86"
version = "0.2.10"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "precomputed-hash"
@@ -835,9 +920,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.24"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
"unicode-xid",
]
@@ -850,9 +935,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.8"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
@@ -917,6 +1002,15 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.5.4"
@@ -942,9 +1036,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "schemars"
version = "0.8.3"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6ab463ae35acccb5cba66c0084c985257b797d288b6050cc2f6ac1b266cb78"
checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409"
dependencies = [
"dyn-clone",
"schemars_derive",
@@ -954,9 +1048,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.3"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "902fdfbcf871ae8f653bddf4b2c05905ddaabc08f69d32a915787e3be0d31356"
checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8"
dependencies = [
"proc-macro2",
"quote",
@@ -971,10 +1065,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "serde"
version = "1.0.122"
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "974ef1bd2ad8a507599b336595454081ff68a9599b4890af7643c0c0ed73a62c"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
@@ -990,9 +1090,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.122"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dee1f300f838c8ac340ecb0112b3ac472464fa67e87292bdb3dfc9c49128e17"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
@@ -1012,9 +1112,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.61"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
@@ -1046,9 +1146,9 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.9.5"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
@@ -1059,9 +1159,9 @@ dependencies = [
[[package]]
name = "signature"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
dependencies = [
"digest 0.9.0",
"rand_core 0.6.3",
@@ -1075,15 +1175,15 @@ checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
[[package]]
name = "smallvec"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "spki"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "987637c5ae6b3121aba9d513f869bd2bff11c4cc086c22473befd6649c0bd521"
checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
dependencies = [
"der",
]
@@ -1102,12 +1202,13 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"parking_lot",
"phf_shared",
"precomputed-hash",
"serde",
@@ -1146,15 +1247,15 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "subtle"
version = "2.4.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "swc_atoms"
version = "0.2.7"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "837a3ef86c2817228e733b6f173c821fd76f9eb21a0bc9001a826be48b00b4e7"
checksum = "9f5229fe227ff0060e13baa386d6e368797700eab909523f730008d191ee53ae"
dependencies = [
"string_cache",
"string_cache_codegen",
@@ -1254,9 +1355,9 @@ dependencies = [
[[package]]
name = "swc_macros_common"
version = "0.3.3"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ed2e930f5a1a4071fe62c90fd3a296f6030e5d94bfe13993244423caf59a78"
checksum = "bf7c68e78ffbcba3d38abe6d0b76a0e1a37888b5c9301db3426537207090ada3"
dependencies = [
"pmutil",
"proc-macro2",
@@ -1266,9 +1367,9 @@ dependencies = [
[[package]]
name = "swc_visit"
version = "0.2.6"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a423caa0b4585118164dbad8f1ad52b592a9a9370b25decc4d84c6b4309132c0"
checksum = "f8511a4788ab29daf00bee23e425aac92c9be4eec74c98fec4a45d0e710be695"
dependencies = [
"either",
"swc_visit_macros",
@@ -1290,9 +1391,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.65"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
"proc-macro2",
"quote",
@@ -1301,18 +1402,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.23"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.23"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
@@ -1321,9 +1422,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a776787d9c5d455bec3db044586ccdd8a9c74d5da5dc319fb80f3db08808fe6"
checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd"
dependencies = [
"libc",
"time-macros",
@@ -1331,15 +1432,15 @@ dependencies = [
[[package]]
name = "time-macros"
version = "0.2.1"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04a153416002296880a3b51329a0e3df31c779c53ec827993e865ce427982843"
checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
[[package]]
name = "tinyvec"
version = "1.3.1"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338"
checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
dependencies = [
"tinyvec_macros",
]
@@ -1383,9 +1484,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.13.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "ucd-trie"
@@ -1395,9 +1496,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "uint"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e"
checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f"
dependencies = [
"byteorder",
"crunchy",
@@ -1407,12 +1508,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
version = "0.3.5"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
dependencies = [
"matches",
]
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
@@ -1431,9 +1529,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
@@ -1466,7 +1564,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "zeroize"
version = "1.3.0"
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
+1
View File
@@ -49,3 +49,4 @@ thiserror = { version = "1.0.23" }
[dev-dependencies]
cosmwasm-schema = { version = "0.14.0" }
fixed = "1.1"
+56 -4
View File
@@ -1,6 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::u128;
use crate::helpers::calculate_epoch_reward_rate;
use crate::state::State;
use crate::storage::{config, layer_distribution};
@@ -10,7 +12,7 @@ use cosmwasm_std::{
entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, QueryResponse,
Response, Uint128,
};
use mixnet_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, StateParams};
use mixnet_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, MixNode, QueryMsg, StateParams};
pub const INITIAL_DEFAULT_EPOCH_LENGTH: u32 = 2;
@@ -26,9 +28,13 @@ pub const INITIAL_GATEWAY_BOND_REWARD_RATE: u64 = 110;
pub const INITIAL_MIXNODE_DELEGATION_REWARD_RATE: u64 = 110;
pub const INITIAL_GATEWAY_DELEGATION_REWARD_RATE: u64 = 110;
pub const INITIAL_MIXNODE_ACTIVE_SET_SIZE: u32 = 100;
pub const INITIAL_MIXNODE_ACTIVE_SET_SIZE: u32 = 5000;
pub const INITIAL_GATEWAY_ACTIVE_SET_SIZE: u32 = 20;
pub const INITIAL_REWARD_POOL: u128 = 250_000_000_000_000;
pub const EPOCH_REWARD_PERCENT: u8 = 2; // Used to calculate epoch reward pool
pub const DEFAULT_SYBIL_RESISTANCE_PERCENT: u8 = 30;
fn default_initial_state(owner: Addr) -> State {
let mixnode_bond_reward_rate = Decimal::percent(INITIAL_MIXNODE_BOND_REWARD_RATE);
let gateway_bond_reward_rate = Decimal::percent(INITIAL_GATEWAY_BOND_REWARD_RATE);
@@ -110,6 +116,9 @@ pub fn execute(
ExecuteMsg::RewardMixnode { identity, uptime } => {
transactions::try_reward_mixnode(deps, env, info, identity, uptime)
}
ExecuteMsg::RewardMixnodeV2 { identity, params } => {
transactions::try_reward_mixnode_v2(deps, env, info, identity, params)
}
ExecuteMsg::RewardGateway { identity, uptime } => {
transactions::try_reward_gateway(deps, env, info, identity, uptime)
}
@@ -207,13 +216,56 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
gateway_identity,
address,
)?),
QueryMsg::GetRewardPool {} => to_binary(&queries::query_reward_pool(deps)),
QueryMsg::GetCirculatingSupply {} => to_binary(&queries::query_circulating_supply(deps)),
QueryMsg::GetEpochRewardPercent {} => to_binary(&EPOCH_REWARD_PERCENT),
QueryMsg::GetSybilResistancePercent {} => to_binary(&DEFAULT_SYBIL_RESISTANCE_PERCENT),
};
Ok(query_res?)
}
#[entry_point]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
use crate::storage::{mixnodes, PREFIX_MIXNODES};
use cosmwasm_std::{Coin, Order};
use cosmwasm_storage::bucket_read;
use mixnet_contract::{Layer, MixNodeBond};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct OldMixNodeBond {
pub bond_amount: Coin,
pub total_delegation: Coin,
pub owner: Addr,
pub layer: Layer,
pub block_height: u64,
pub mix_node: MixNode,
}
impl From<OldMixNodeBond> for MixNodeBond {
fn from(o: OldMixNodeBond) -> MixNodeBond {
MixNodeBond {
bond_amount: o.bond_amount,
total_delegation: o.total_delegation,
owner: o.owner,
layer: o.layer,
block_height: o.block_height,
mix_node: o.mix_node,
profit_margin_percent: Some(10),
}
}
}
let mixnode_bonds = bucket_read(deps.storage, PREFIX_MIXNODES)
.range(None, None, Order::Ascending)
.take_while(Result::is_ok)
.map(Result::unwrap)
.map(|(key, bond): (Vec<u8>, OldMixNodeBond)| (key, bond.into()))
.collect::<Vec<(Vec<u8>, MixNodeBond)>>();
for (key, bond) in mixnode_bonds {
mixnodes(deps.storage).save(&key, &bond)?;
}
Ok(Default::default())
}
+6
View File
@@ -89,4 +89,10 @@ pub enum ContractError {
identity: IdentityKey,
address: Addr,
},
#[error("Overflow error!")]
Overflow(#[from] cosmwasm_std::OverflowError),
#[error("Invalid ratio")]
Ratio(#[from] mixnet_contract::error::MixnetContractError),
}
+2 -2
View File
@@ -19,11 +19,11 @@ const DECIMAL_FRACTIONAL: Uint128 = Uint128(1_000_000_000_000_000_000u128);
// cosmwasm bucket internal value
const NAMESPACE_LENGTH: usize = 2;
fn decimal_to_uint128(value: Decimal) -> Uint128 {
pub fn decimal_to_uint128(value: Decimal) -> Uint128 {
value * DECIMAL_FRACTIONAL
}
fn uint128_to_decimal(value: Uint128) -> Decimal {
pub fn uint128_to_decimal(value: Uint128) -> Decimal {
Decimal::from_ratio(value, DECIMAL_FRACTIONAL)
}
+13 -5
View File
@@ -4,13 +4,13 @@
use crate::error::ContractError;
use crate::helpers::get_all_delegations_paged;
use crate::storage::{
all_gateway_delegations_read, all_mix_delegations_read, gateway_delegations_read,
gateways_owners_read, gateways_read, mix_delegations_read, mixnodes_owners_read, mixnodes_read,
read_layer_distribution, read_state_params, reverse_gateway_delegations_read,
reverse_mix_delegations_read,
all_gateway_delegations_read, all_mix_delegations_read, circulating_supply,
gateway_delegations_read, gateways_owners_read, gateways_read, mix_delegations_read,
mixnodes_owners_read, mixnodes_read, read_layer_distribution, read_state_params,
reverse_gateway_delegations_read, reverse_mix_delegations_read, reward_pool_value,
};
use config::defaults::DENOM;
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult};
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult, Uint128};
use mixnet_contract::{
Delegation, GatewayBond, GatewayOwnershipResponse, IdentityKey, LayerDistribution, MixNodeBond,
MixOwnershipResponse, PagedAllDelegationsResponse, PagedGatewayDelegationsResponse,
@@ -93,6 +93,14 @@ pub(crate) fn query_layer_distribution(deps: Deps) -> LayerDistribution {
read_layer_distribution(deps.storage)
}
pub(crate) fn query_reward_pool(deps: Deps) -> Uint128 {
reward_pool_value(deps.storage)
}
pub(crate) fn query_circulating_supply(deps: Deps) -> Uint128 {
circulating_supply(deps.storage)
}
/// Adds a 0 byte to terminate the `start_after` value given. This allows CosmWasm
/// to get the succeeding key as the start of the next page.
// S works for both `String` and `Addr` and that's what we wanted
+97 -3
View File
@@ -1,14 +1,16 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::queries;
use crate::contract::INITIAL_REWARD_POOL;
use crate::state::State;
use crate::transactions::MINIMUM_BLOCK_AGE_FOR_REWARDING;
use crate::{error::ContractError, queries};
use config::defaults::TOTAL_SUPPLY;
use cosmwasm_std::{Decimal, Order, StdResult, Storage, Uint128};
use cosmwasm_storage::{
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
Singleton,
};
use mixnet_contract::mixnode::NodeRewardParams;
use mixnet_contract::{
Addr, GatewayBond, IdentityKey, IdentityKeyRef, Layer, LayerDistribution, MixNodeBond,
RawDelegationData, StateParams,
@@ -24,9 +26,10 @@ use serde::Serialize;
// singletons
const CONFIG_KEY: &[u8] = b"config";
const LAYER_DISTRIBUTION_KEY: &[u8] = b"layers";
const REWARD_POOL_PREFIX: &[u8] = b"pool";
// buckets
const PREFIX_MIXNODES: &[u8] = b"mn";
pub const PREFIX_MIXNODES: &[u8] = b"mn";
const PREFIX_MIXNODES_OWNERS: &[u8] = b"mo";
const PREFIX_GATEWAYS: &[u8] = b"gt";
const PREFIX_GATEWAYS_OWNERS: &[u8] = b"go";
@@ -48,6 +51,46 @@ pub fn config_read(storage: &dyn Storage) -> ReadonlySingleton<State> {
singleton_read(storage, CONFIG_KEY)
}
fn reward_pool(storage: &dyn Storage) -> ReadonlySingleton<Uint128> {
singleton_read(storage, REWARD_POOL_PREFIX)
}
pub fn mut_reward_pool(storage: &mut dyn Storage) -> Singleton<Uint128> {
singleton(storage, REWARD_POOL_PREFIX)
}
pub fn reward_pool_value(storage: &dyn Storage) -> Uint128 {
match reward_pool(storage).load() {
Ok(value) => value,
Err(_e) => Uint128(INITIAL_REWARD_POOL),
}
}
#[allow(dead_code)]
pub fn incr_reward_pool(
amount: Uint128,
storage: &mut dyn Storage,
) -> Result<Uint128, ContractError> {
let stake = reward_pool_value(storage).saturating_add(amount);
mut_reward_pool(storage).save(&stake)?;
Ok(stake)
}
pub fn decr_reward_pool(
amount: Uint128,
storage: &mut dyn Storage,
) -> Result<Uint128, ContractError> {
// TODO: This could got to < 0
let stake = reward_pool_value(storage).checked_sub(amount)?;
mut_reward_pool(storage).save(&stake)?;
Ok(stake)
}
pub fn circulating_supply(storage: &dyn Storage) -> Uint128 {
let reward_pool = reward_pool_value(storage).u128();
Uint128(TOTAL_SUPPLY - reward_pool)
}
pub(crate) fn read_state_params(storage: &dyn Storage) -> StateParams {
// note: In any other case, I wouldn't have attempted to unwrap this result, but in here
// if we fail to load the stored state we would already be in the undefined behaviour land,
@@ -214,6 +257,56 @@ pub(crate) fn increase_mix_delegated_stakes(
Ok(total_rewarded)
}
pub(crate) fn increase_mix_delegated_stakes_v2(
storage: &mut dyn Storage,
bond: &MixNodeBond,
params: &NodeRewardParams,
) -> Result<Uint128, ContractError> {
let chunk_size = queries::DELEGATION_PAGE_MAX_LIMIT as usize;
let mut total_rewarded = Uint128::zero();
let mut chunk_start: Option<Vec<_>> = None;
loop {
// get `chunk_size` of delegations
let delegations_chunk = mix_delegations_read(storage, bond.identity())
.range(chunk_start.as_deref(), None, Order::Ascending)
.take(chunk_size)
.collect::<StdResult<Vec<_>>>()?;
if delegations_chunk.is_empty() {
break;
}
// append 0 byte to the last value to start with whatever is the next succeeding key
chunk_start = Some(
delegations_chunk
.last()
.unwrap()
.0
.iter()
.cloned()
.chain(std::iter::once(0u8))
.collect(),
);
// and for each of them increase the stake proportionally to the reward
// if at least `MINIMUM_BLOCK_AGE_FOR_REWARDING` blocks have been created
// since they delegated
for (delegator_address, mut delegation) in delegations_chunk.into_iter() {
if delegation.block_height + MINIMUM_BLOCK_AGE_FOR_REWARDING
<= params.reward_blockstamp()
{
let reward = bond.reward_delegation(delegation.amount, params);
delegation.amount += Uint128(reward);
total_rewarded += Uint128(reward);
mix_delegations(storage, bond.identity()).save(&delegator_address, &delegation)?;
}
}
}
Ok(total_rewarded)
}
pub(crate) fn increase_gateway_delegated_stakes(
storage: &mut dyn Storage,
gateway_identity: IdentityKeyRef,
@@ -471,6 +564,7 @@ mod tests {
identity_key: node_identity.clone(),
..mix_node_fixture()
},
profit_margin_percent: Some(10),
};
mixnodes(&mut storage)
+1
View File
@@ -133,6 +133,7 @@ pub mod helpers {
Layer::One,
12_345,
mix_node,
None,
)
}
+202 -9
View File
@@ -1,6 +1,5 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::ContractError;
use crate::helpers::{calculate_epoch_reward_rate, scale_reward_by_uptime, Delegations};
use crate::queries;
@@ -10,6 +9,7 @@ use cosmwasm_std::{
attr, coins, BankMsg, Coin, Decimal, DepsMut, Env, MessageInfo, Response, StdResult, Uint128,
};
use cosmwasm_storage::ReadonlyBucket;
use mixnet_contract::mixnode::NodeRewardParams;
use mixnet_contract::{
Gateway, GatewayBond, IdentityKey, Layer, MixNode, MixNodeBond, RawDelegationData, StateParams,
};
@@ -99,6 +99,7 @@ pub(crate) fn try_add_mixnode(
layer,
env.block.height,
mix_node,
None,
);
// this might potentially require more gas if a significant number of delegations was there
@@ -443,6 +444,66 @@ pub(crate) fn try_reward_mixnode(
})
}
pub(crate) fn try_reward_mixnode_v2(
deps: DepsMut,
env: Env,
info: MessageInfo,
mix_identity: IdentityKey,
params: NodeRewardParams,
) -> Result<Response, ContractError> {
let state = config_read(deps.storage).load().unwrap();
// check if this is executed by the monitor, if not reject the transaction
if info.sender != state.network_monitor_address {
return Err(ContractError::Unauthorized);
}
// check if the bond even exists
let mut current_bond = match mixnodes_read(deps.storage).load(mix_identity.as_bytes()) {
Ok(bond) => bond,
Err(_) => {
return Ok(Response {
attributes: vec![attr("result", "bond not found")],
..Default::default()
});
}
};
let mut reward_params = params;
reward_params.set_reward_blockstamp(env.block.height);
let reward_result = current_bond.reward(&reward_params);
// Omitting the price per packet function now, it follows that base operator reward is the node_reward
let operator_reward = current_bond.operator_reward(&reward_params);
let total_delegation_reward =
increase_mix_delegated_stakes_v2(deps.storage, &current_bond, &reward_params)?;
// update current bond with the reward given to the node and the delegators
// if it has been bonded for long enough
if current_bond.block_height + MINIMUM_BLOCK_AGE_FOR_REWARDING
<= reward_params.reward_blockstamp()
{
current_bond.bond_amount.amount += Uint128(operator_reward);
current_bond.total_delegation.amount += total_delegation_reward;
mixnodes(deps.storage).save(mix_identity.as_bytes(), &current_bond)?;
decr_reward_pool(Uint128(operator_reward), deps.storage)?;
decr_reward_pool(total_delegation_reward, deps.storage)?;
}
Ok(Response {
submessages: vec![],
messages: vec![],
attributes: vec![
attr("bond increase", reward_result.reward()),
attr("total delegation increase", total_delegation_reward),
],
data: None,
})
}
// Note: if any changes are made to this function or anything it is calling down the stack,
// for example delegation reward distribution, the gas limits must be retested and both
// validator-api/src/rewarding/mod.rs::{GATEWAY_REWARD_OP_BASE_GAS_LIMIT, PER_GATEWAY_DELEGATION_GAS_INCREASE}
@@ -561,8 +622,10 @@ pub(crate) fn try_delegate_to_mixnode(
}
};
let amount = info.funds[0].amount;
// update total_delegation of this node
current_bond.total_delegation.amount += info.funds[0].amount;
current_bond.total_delegation.amount += amount;
mixnodes_bucket.save(mix_identity.as_bytes(), &current_bond)?;
let mut delegation_bucket = mix_delegations(deps.storage, &mix_identity);
@@ -570,8 +633,8 @@ pub(crate) fn try_delegate_to_mixnode(
// write the delegation
let new_amount = match delegation_bucket.may_load(sender_bytes)? {
Some(existing_delegation) => existing_delegation.amount + info.funds[0].amount,
None => info.funds[0].amount,
Some(existing_delegation) => existing_delegation.amount + amount,
None => amount,
};
// the block height is reset, if it existed
let new_delegation = RawDelegationData::new(new_amount, env.block.height);
@@ -727,10 +790,10 @@ pub(crate) fn try_remove_delegation_from_gateway(
pub mod tests {
use super::*;
use crate::contract::{
execute, query, INITIAL_DEFAULT_EPOCH_LENGTH, INITIAL_GATEWAY_BOND,
INITIAL_GATEWAY_BOND_REWARD_RATE, INITIAL_GATEWAY_DELEGATION_REWARD_RATE,
INITIAL_MIXNODE_BOND, INITIAL_MIXNODE_BOND_REWARD_RATE,
INITIAL_MIXNODE_DELEGATION_REWARD_RATE,
execute, query, DEFAULT_SYBIL_RESISTANCE_PERCENT, INITIAL_DEFAULT_EPOCH_LENGTH,
INITIAL_GATEWAY_BOND, INITIAL_GATEWAY_BOND_REWARD_RATE,
INITIAL_GATEWAY_DELEGATION_REWARD_RATE, INITIAL_MIXNODE_BOND,
INITIAL_MIXNODE_BOND_REWARD_RATE, INITIAL_MIXNODE_DELEGATION_REWARD_RATE,
};
use crate::helpers::calculate_epoch_reward_rate;
use crate::queries::DELEGATION_PAGE_DEFAULT_LIMIT;
@@ -1811,6 +1874,7 @@ pub mod tests {
identity_key: node_identity.clone(),
..mix_node_fixture()
},
profit_margin_percent: Some(10),
};
mixnodes(deps.as_mut().storage)
@@ -1910,6 +1974,7 @@ pub mod tests {
identity_key: node_identity.clone(),
..mix_node_fixture()
},
profit_margin_percent: Some(10),
};
mixnodes(deps.as_mut().storage)
@@ -3494,7 +3559,7 @@ pub mod tests {
}
#[test]
fn delegation_is_not_removed_if_node_unbonded() {
fn delegation_is_not_removed_if_gateway_unbonded() {
let mut deps = helpers::init_contract();
let gateway_owner = "bob";
@@ -4001,4 +4066,132 @@ pub mod tests {
assert_eq!(bob_node.mix_node.identity_key, "bob");
assert_eq!(bob_node.layer, Layer::Two);
}
#[test]
fn test_tokenomics_rewarding() {
use crate::contract::{EPOCH_REWARD_PERCENT, INITIAL_REWARD_POOL};
type U128 = fixed::types::U75F53;
let mut deps = helpers::init_contract();
let mut env = mock_env();
let current_state = config(deps.as_mut().storage).load().unwrap();
let network_monitor_address = current_state.network_monitor_address;
let period_reward_pool = (INITIAL_REWARD_POOL / 100) * EPOCH_REWARD_PERCENT as u128;
assert_eq!(period_reward_pool, 5_000_000_000_000);
let k = 200; // Imagining our active set size is 200
let circulating_supply = circulating_supply(&deps.storage).u128();
assert_eq!(circulating_supply, 750_000_000_000_000u128);
// mut_reward_pool(deps.as_mut().storage)
// .save(&Uint128(period_reward_pool))
// .unwrap();
try_add_mixnode(
deps.as_mut(),
mock_env(),
mock_info(
"alice",
&vec![Coin {
denom: DENOM.to_string(),
amount: Uint128(10000_000_000),
}],
),
MixNode {
identity_key: "alice".to_string(),
..helpers::mix_node_fixture()
},
)
.unwrap();
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("d1", &vec![coin(8000_000000, DENOM)]),
"alice".to_string(),
)
.unwrap();
try_delegate_to_mixnode(
deps.as_mut(),
mock_env(),
mock_info("d2", &vec![coin(2000_000000, DENOM)]),
"alice".to_string(),
)
.unwrap();
let total_uptime = 200_000;
let info = mock_info(network_monitor_address.as_ref(), &[]);
env.block.height += 2 * MINIMUM_BLOCK_AGE_FOR_REWARDING;
let mix_1 = mixnodes_read(&deps.storage).load(b"alice").unwrap();
let mix_1_uptime = 100;
let _mix_1_performance = Decimal::from_ratio(mix_1_uptime, total_uptime);
let mut params = NodeRewardParams::new(
period_reward_pool,
k,
total_uptime,
0,
circulating_supply,
mix_1_uptime,
DEFAULT_SYBIL_RESISTANCE_PERCENT,
);
params.set_reward_blockstamp(env.block.height);
assert_eq!(params.performance(), 1);
let mix_1_reward_result = mix_1.reward(&params);
assert_eq!(
mix_1_reward_result.sigma(),
U128::from_num(0.0000266666666666)
);
assert_eq!(
mix_1_reward_result.lambda(),
U128::from_num(0.0000133333333333)
);
assert_eq!(mix_1_reward_result.reward().int(), 102646153);
let mix1_operator_profit = mix_1.operator_reward(&params);
let mix1_delegator1_reward = mix_1.reward_delegation(Uint128(8000_000000), &params);
let mix1_delegator2_reward = mix_1.reward_delegation(Uint128(2000_000000), &params);
assert_eq!(mix1_operator_profit, U128::from_num(74455384));
assert_eq!(mix1_delegator1_reward, U128::from_num(22552615));
assert_eq!(mix1_delegator2_reward, U128::from_num(5638153));
let pre_reward_bond = read_mixnode_bond(&deps.storage, b"alice").unwrap().u128();
assert_eq!(pre_reward_bond, 10000_000_000);
let pre_reward_delegation = read_mixnode_delegation(&deps.storage, b"alice")
.unwrap()
.u128();
assert_eq!(pre_reward_delegation, 10000_000_000);
try_reward_mixnode_v2(deps.as_mut(), env, info, "alice".to_string(), params).unwrap();
assert_eq!(
read_mixnode_bond(&deps.storage, b"alice").unwrap().u128(),
U128::from_num(pre_reward_bond) + U128::from_num(mix1_operator_profit)
);
assert_eq!(
read_mixnode_delegation(&deps.storage, b"alice")
.unwrap()
.u128(),
pre_reward_delegation + mix1_delegator1_reward + mix1_delegator2_reward
);
assert_eq!(
reward_pool_value(&deps.storage).u128(),
U128::from_num(INITIAL_REWARD_POOL)
- (U128::from_num(mix1_operator_profit)
+ U128::from_num(mix1_delegator1_reward)
+ U128::from_num(mix1_delegator2_reward))
)
}
}
@@ -55,8 +55,8 @@ impl<'a> GatewayHandshake<'a> {
)
.await?;
let remote_identity = init_message.local_id_pubkey();
let remote_ephemeral_key = init_message.ephemeral_key();
let remote_identity = init_message.0;
let remote_ephemeral_key = init_message.1;
state.update_remote_identity(remote_identity);
// hkdf::<blake3>::(g^xy)
@@ -15,46 +15,9 @@ use futures::{Sink, SinkExt, Stream, StreamExt};
use log::*;
use nymsphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use tungstenite::Message as WsMessage;
#[derive(Serialize, Deserialize)]
pub struct InitMessage {
local_id_pubkey: [u8; identity::PUBLIC_KEY_LENGTH],
ephemeral_key: [u8; identity::PUBLIC_KEY_LENGTH],
}
impl InitMessage {
fn new(local_id_pubkey: &identity::PublicKey, ephemeral_key: &encryption::PublicKey) -> Self {
InitMessage {
local_id_pubkey: local_id_pubkey.to_bytes(),
ephemeral_key: ephemeral_key.to_bytes(),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn local_id_pubkey(&self) -> identity::PublicKey {
identity::PublicKey::from_bytes(&self.local_id_pubkey).unwrap()
}
#[cfg(not(target_arch = "wasm32"))]
pub fn ephemeral_key(&self) -> encryption::PublicKey {
encryption::PublicKey::from_bytes(&self.ephemeral_key).unwrap()
}
fn to_bytes(&self) -> Vec<u8> {
bincode::serialize(self).unwrap()
}
}
impl TryFrom<&[u8]> for InitMessage {
type Error = HandshakeError;
fn try_from(value: &[u8]) -> Result<InitMessage, Self::Error> {
bincode::deserialize(value).map_err(|e| e.into())
}
}
/// Handshake state.
pub(crate) struct State<'a, S> {
/// The underlying WebSocket stream.
@@ -92,7 +55,6 @@ impl<'a, S> State<'a, S> {
}
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn local_ephemeral_key(&self) -> &encryption::PublicKey {
self.ephemeral_keypair.public_key()
}
@@ -101,17 +63,40 @@ impl<'a, S> State<'a, S> {
// Eventually the ID_PUBKEY prefix will get removed and recipient will know
// initializer's identity from another source.
pub(crate) fn init_message(&self) -> Vec<u8> {
InitMessage::new(
self.identity.public_key(),
self.ephemeral_keypair.public_key(),
)
.to_bytes()
self.identity
.public_key()
.to_bytes()
.iter()
.cloned()
.chain(
self.ephemeral_keypair
.public_key()
.to_bytes()
.iter()
.cloned(),
)
.collect()
}
// this will need to be adjusted when REMOTE_ID_PUBKEY is removed
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn parse_init_message(init_message: Vec<u8>) -> Result<InitMessage, HandshakeError> {
InitMessage::try_from(init_message.as_slice()).map_err(|_| HandshakeError::MalformedRequest)
pub(crate) fn parse_init_message(
mut init_message: Vec<u8>,
) -> Result<(identity::PublicKey, encryption::PublicKey), HandshakeError> {
if init_message.len() != identity::PUBLIC_KEY_LENGTH + encryption::PUBLIC_KEY_SIZE {
return Err(HandshakeError::MalformedRequest);
}
let remote_ephemeral_key_bytes = init_message.split_off(identity::PUBLIC_KEY_LENGTH);
// this can only fail if the provided bytes have len different from encryption::PUBLIC_KEY_SIZE
// which is impossible
let remote_ephemeral_key =
encryption::PublicKey::from_bytes(&remote_ephemeral_key_bytes).unwrap();
// this could actually fail if the curve point fails to get decompressed
let remote_identity = identity::PublicKey::from_bytes(&init_message)
.map_err(|_| HandshakeError::MalformedRequest)?;
Ok((remote_identity, remote_ephemeral_key))
}
pub(crate) fn derive_shared_key(&mut self, remote_ephemeral_key: &encryption::PublicKey) {
@@ -208,7 +193,6 @@ impl<'a, S> State<'a, S> {
.map_err(|_| HandshakeError::InvalidSignature)
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn update_remote_identity(&mut self, remote_pubkey: identity::PublicKey) {
self.remote_pubkey = Some(remote_pubkey)
}
+35
View File
@@ -148,6 +148,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "backtrace"
version = "0.3.61"
@@ -321,6 +327,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -1235,6 +1247,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixed"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "flate2"
version = "1.0.21"
@@ -1775,6 +1799,12 @@ dependencies = [
"tracing",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "3.5.5"
@@ -2371,10 +2401,15 @@ dependencies = [
name = "mixnet-contract"
version = "0.1.0"
dependencies = [
"az",
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
"thiserror",
"ts-rs",
]
+3
View File
@@ -39,6 +39,7 @@ getset = "0.1.1"
rocket_sync_db_pools = {version = "0.1.0-rc.1", default-features = false}
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]}
## internal
config = { path = "../common/config" }
crypto = { path="../common/crypto" }
@@ -53,6 +54,8 @@ credentials = { path = "../common/credentials", optional = true }
[features]
coconut = ["coconut-interface", "credentials", "gateway-client/coconut"]
default = ["tokenomics"]
tokenomics = []
[build-dependencies]
tokio = { version = "1.4", features = ["rt-multi-thread", "macros"] }
+2 -2
View File
@@ -78,7 +78,7 @@ impl<C> ValidatorCacheRefresher<C> {
{
let (mixnodes, gateways) = tokio::try_join!(
self.nymd_client.get_mixnodes(),
self.nymd_client.get_gateways()
self.nymd_client.get_gateways(),
)?;
let state_params = self.nymd_client.get_state_params().await?;
@@ -86,7 +86,7 @@ impl<C> ValidatorCacheRefresher<C> {
info!(
"Updating validator cache. There are {} mixnodes and {} gateways",
mixnodes.len(),
gateways.len()
gateways.len(),
);
self.cache
+28
View File
@@ -94,6 +94,34 @@ impl<C> Client<C> {
Ok(time)
}
pub(crate) async fn get_reward_pool(&self) -> Result<u128, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.0.read().await.get_reward_pool().await?)
}
pub(crate) async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.0.read().await.get_circulating_supply().await?)
}
pub(crate) async fn get_sybil_resistance_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.0.read().await.get_sybil_resistance_percent().await?)
}
pub(crate) async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.0.read().await.get_epoch_reward_percent().await?)
}
pub(crate) async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
+59 -4
View File
@@ -13,6 +13,7 @@ use crate::storage::models::{
};
use crate::storage::NodeStatusStorage;
use log::{error, info};
use mixnet_contract::mixnode::NodeRewardParams;
use mixnet_contract::{ExecuteMsg, IdentityKey};
use rand::{thread_rng, Rng};
use std::collections::HashMap;
@@ -54,6 +55,19 @@ pub(crate) struct MixnodeToReward {
/// Total number of individual addresses that have delegated to this particular node
pub(crate) total_delegations: usize,
/// Node absolute uptime over total active set uptime
params: Option<NodeRewardParams>,
}
impl MixnodeToReward {
/// Somewhat clumsy way of feature gatting tokenomics payments. In a tokenomics scenario this will never be None at reward time. We levarage that to Into a different ExecuteMsg variant
fn params(&self) -> Option<NodeRewardParams> {
if cfg!(feature = "tokenomics") {
self.params
} else {
None
}
}
}
#[derive(Debug, Clone)]
@@ -83,9 +97,16 @@ pub(crate) struct FailureData {
impl<'a> From<&'a MixnodeToReward> for ExecuteMsg {
fn from(node: &MixnodeToReward) -> Self {
ExecuteMsg::RewardMixnode {
identity: node.identity.clone(),
uptime: node.uptime.u8() as u32,
if let Some(params) = node.params() {
ExecuteMsg::RewardMixnodeV2 {
identity: node.identity.clone(),
params,
}
} else {
ExecuteMsg::RewardMixnode {
identity: node.identity.clone(),
uptime: node.uptime.u8() as u32,
}
}
}
}
@@ -270,12 +291,13 @@ impl Rewarder {
// by people hesitating to delegate to nodes without them and thus those nodes disappearing
// from the active set (once introduced)
let mixnode_delegators = self.produce_active_mixnode_delegators_map().await?;
let state = self.nymd_client.get_state_params().await?;
// 1. go through all active mixnodes
// 2. filter out nodes that are currently not in the active set (as `mixnode_delegators` was obtained by
// querying the validator)
// 3. determine uptime and attach delegators count
let eligible_nodes = active_mixnodes
let mut eligible_nodes: Vec<MixnodeToReward> = active_mixnodes
.iter()
.filter_map(|mix| {
mixnode_delegators
@@ -285,11 +307,44 @@ impl Rewarder {
uptime: self
.calculate_absolute_uptime(mix.last_day_ipv4, mix.last_day_ipv6),
total_delegations,
params: None,
})
})
.filter(|node| node.uptime.u8() > 0)
.collect();
if cfg!(feature = "tokenomics") {
let total_epoch_uptime = eligible_nodes
.iter()
.fold(0, |acc, mix| acc + mix.uptime.u8() as u128);
let reward_pool = self.nymd_client.get_reward_pool().await?;
let circulating_supply = self.nymd_client.get_circulating_supply().await?;
let sybil_resistance_percent = self.nymd_client.get_sybil_resistance_percent().await?;
let epoch_reward_percent = self.nymd_client.get_epoch_reward_percent().await?;
let k = state.mixnode_active_set_size;
let period_reward_pool = (reward_pool / 100) * epoch_reward_percent as u128;
info!("Rewarding pool stats");
info!("-- Reward pool: {} unym", reward_pool);
info!("---- Epoch reward pool: {} unym", period_reward_pool);
info!("-- Circulating supply: {} unym", circulating_supply);
for mix in eligible_nodes.iter_mut() {
mix.params = Some(NodeRewardParams::new(
period_reward_pool,
k.into(),
total_epoch_uptime,
0,
circulating_supply,
mix.uptime.u8().into(),
sybil_resistance_percent,
));
}
} else {
info!("Tokenomics feature is OFF");
}
Ok(eligible_nodes)
}