Feature/active sets (#764)
* Added separate gateway active set size * Grabbing contract state * Defined PartialOrd on MixnodeBond and GatewayBond * Some initial stub for active set * Unit tests for mixnode and gateway bond partialord implementation * Obtaining active sets * Active nodes routes * Additional methods on validator client * Added state migration * Feature locking unused import * Fixed State test fixture * Included block height for partial_ord * Missing post-merge imports * api on the client for active nodes * Native/socks5/wasm clients using active nodes * Rewarding only active nodes * Updated validator client StateParams definition * Gateway active set size * Contract migration update * Cargo fmt * Updated TauriStateParams * [ci skip] Generate TS types Co-authored-by: jstuczyn <jstuczyn@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
e891c68158
commit
668325a4ce
@@ -107,7 +107,7 @@ impl TopologyAccessor {
|
||||
self.inner.read().await.into()
|
||||
}
|
||||
|
||||
async fn update_global_topology(&mut self, new_topology: Option<NymTopology>) {
|
||||
async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||
self.inner.write().await.update(new_topology);
|
||||
}
|
||||
|
||||
@@ -130,19 +130,26 @@ impl Default for TopologyAccessor {
|
||||
pub struct TopologyRefresherConfig {
|
||||
validator_api_urls: Vec<Url>,
|
||||
refresh_rate: time::Duration,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(validator_api_urls: Vec<Url>, refresh_rate: time::Duration) -> Self {
|
||||
pub fn new(
|
||||
validator_api_urls: Vec<Url>,
|
||||
refresh_rate: time::Duration,
|
||||
client_version: String,
|
||||
) -> Self {
|
||||
TopologyRefresherConfig {
|
||||
validator_api_urls,
|
||||
refresh_rate,
|
||||
client_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
validator_client: validator_client::ApiClient,
|
||||
client_version: String,
|
||||
|
||||
validator_api_urls: Vec<Url>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
@@ -158,6 +165,7 @@ impl TopologyRefresher {
|
||||
|
||||
TopologyRefresher {
|
||||
validator_client: validator_client::ApiClient::new(cfg.validator_api_urls[0].clone()),
|
||||
client_version: cfg.client_version,
|
||||
validator_api_urls: cfg.validator_api_urls,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
@@ -177,12 +185,71 @@ impl TopologyRefresher {
|
||||
.change_validator_api(self.validator_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
///
|
||||
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `topology`: active topology constructed from validator api data
|
||||
/// * `mixnodes_count`: total number of active mixnodes
|
||||
fn check_layer_distribution(
|
||||
&self,
|
||||
active_topology: &NymTopology,
|
||||
mixnodes_count: usize,
|
||||
) -> bool {
|
||||
let mixes = active_topology.mixes();
|
||||
if active_topology.gateways().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// trivial check to see if have at least a single node on each layer (regardless of active set size)
|
||||
if mixes.get(&1).is_none() || mixes.get(&2).is_none() || mixes.get(&3).is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let upper_bound = (mixnodes_count as f32 * 0.66) as usize;
|
||||
let lower_bound = (mixnodes_count as f32 * 0.15) as usize;
|
||||
|
||||
let layer1 = mixes.get(&1).unwrap().len();
|
||||
let layer2 = mixes.get(&2).unwrap().len();
|
||||
let layer3 = mixes.get(&3).unwrap().len();
|
||||
|
||||
if layer1 < lower_bound || layer1 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer2 < lower_bound || layer2 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer3 < lower_bound || layer3 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||
// TODO: optimization for the future:
|
||||
// only refresh mixnodes on timer and refresh gateways only when
|
||||
// we have to send to a new, unknown, gateway
|
||||
|
||||
let mixnodes = match self.validator_client.get_cached_mixnodes().await {
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {}", err);
|
||||
return None;
|
||||
@@ -190,7 +257,7 @@ impl TopologyRefresher {
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
let gateways = match self.validator_client.get_cached_active_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {}", err);
|
||||
return None;
|
||||
@@ -198,11 +265,16 @@ impl TopologyRefresher {
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_bonds(mixnodes, gateways);
|
||||
let mixnodes_count = mixnodes.len();
|
||||
let topology =
|
||||
nym_topology_from_bonds(mixnodes, gateways).filter_system_version(&self.client_version);
|
||||
|
||||
// TODO: I didn't want to change it now, but the expected system version should rather be put in config
|
||||
// rather than pulled from package version of `client_core`
|
||||
Some(topology.filter_system_version(env!("CARGO_PKG_VERSION")))
|
||||
if !self.check_layer_distribution(&topology, mixnodes_count) {
|
||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||
None
|
||||
} else {
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh(&mut self) {
|
||||
|
||||
@@ -236,6 +236,7 @@ impl NymClient {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
self.config.get_base().get_validator_api_endpoints(),
|
||||
self.config.get_base().get_topology_refresh_rate(),
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||
|
||||
@@ -224,6 +224,7 @@ impl NymClient {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
self.config.get_base().get_validator_api_endpoints(),
|
||||
self.config.get_base().get_topology_refresh_rate(),
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nymproject/nym-validator-client",
|
||||
"version": "0.17.0",
|
||||
"version": "0.18.0",
|
||||
"description": "A TypeScript client for interacting with smart contracts in Nym validators",
|
||||
"repository": "https://github.com/nymtech/nym",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { GatewayBond } from "../types";
|
||||
import {GatewayBond, PagedGatewayResponse} from "../types";
|
||||
import {INetClient} from "../net-client"
|
||||
import {IQueryClient} from "../query-client";
|
||||
import {PagedGatewayResponse, VALIDATOR_API_GATEWAYS, VALIDATOR_API_PORT} from "../index";
|
||||
import {VALIDATOR_API_GATEWAYS, VALIDATOR_API_PORT} from "../index";
|
||||
import axios from "axios";
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { MixNodeBond } from "../types";
|
||||
import {MixNodeBond, PagedMixnodeResponse} from "../types";
|
||||
import { INetClient } from "../net-client"
|
||||
import {IQueryClient} from "../query-client";
|
||||
import {PagedMixnodeResponse, VALIDATOR_API_MIXNODES, VALIDATOR_API_PORT} from "../index";
|
||||
import {VALIDATOR_API_MIXNODES, VALIDATOR_API_PORT} from "../index";
|
||||
import axios from "axios";
|
||||
|
||||
export { MixnodesCache };
|
||||
|
||||
/**
|
||||
* There are serious limits in smart contract systems, but we need to keep track of
|
||||
* There are serious limits in smart contract systems, but we need to keep track of
|
||||
* potentially thousands of nodes. MixnodeCache instances repeatedly make requests for
|
||||
* paged data about what mixnodes exist, and keep them locally in memory so that they're
|
||||
* available for querying.
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import NetClient, { INetClient } from "./net-client";
|
||||
import { Gateway, GatewayBond, MixNode, MixNodeBond, SendRequest } from "./types";
|
||||
import { Bip39, Random } from "@cosmjs/crypto";
|
||||
import { DirectSecp256k1HdWallet, EncodeObject } from "@cosmjs/proto-signing";
|
||||
import NetClient, {INetClient} from "./net-client";
|
||||
import {
|
||||
StateParams,
|
||||
Delegation,
|
||||
PagedMixDelegationsResponse,
|
||||
PagedGatewayDelegationsResponse,
|
||||
MixNodeBond,
|
||||
MixNode,
|
||||
GatewayBond,
|
||||
Gateway,
|
||||
SendRequest
|
||||
} from "./types";
|
||||
import {Bip39, Random} from "@cosmjs/crypto";
|
||||
import {DirectSecp256k1HdWallet, EncodeObject} from "@cosmjs/proto-signing";
|
||||
import MixnodesCache from "./caches/mixnodes";
|
||||
import { buildFeeTable, coin, Coin, coins, StdFee } from "@cosmjs/stargate";
|
||||
import {buildFeeTable, coin, Coin, coins, StdFee} from "@cosmjs/stargate";
|
||||
import {
|
||||
ExecuteResult,
|
||||
InstantiateOptions,
|
||||
@@ -22,17 +32,17 @@ import {
|
||||
nativeToPrintable
|
||||
} from "./currency";
|
||||
import GatewaysCache from "./caches/gateways";
|
||||
import QueryClient, { IQueryClient } from "./query-client";
|
||||
import { nymGasLimits, nymGasPrice } from "./stargate-helper";
|
||||
import { BroadcastTxSuccess, isBroadcastTxFailure } from "@cosmjs/stargate";
|
||||
import { makeBankMsgSend } from "./utils";
|
||||
import QueryClient, {IQueryClient} from "./query-client";
|
||||
import {nymGasLimits, nymGasPrice} from "./stargate-helper";
|
||||
import {BroadcastTxSuccess, isBroadcastTxFailure} from "@cosmjs/stargate";
|
||||
import {makeBankMsgSend} from "./utils";
|
||||
|
||||
export const VALIDATOR_API_PORT = "8080";
|
||||
export const VALIDATOR_API_GATEWAYS = "v1/gateways";
|
||||
export const VALIDATOR_API_MIXNODES = "v1/mixnodes";
|
||||
|
||||
export { coins, coin };
|
||||
export { Coin };
|
||||
export {coins, coin};
|
||||
export {Coin};
|
||||
export {
|
||||
displayAmountToNative,
|
||||
nativeCoinToDisplay,
|
||||
@@ -42,7 +52,7 @@ export {
|
||||
MappedCoin,
|
||||
CoinMap
|
||||
}
|
||||
export { nymGasLimits, nymGasPrice }
|
||||
export {nymGasLimits, nymGasPrice}
|
||||
|
||||
export default class ValidatorClient {
|
||||
private readonly client: INetClient | IQueryClient
|
||||
@@ -619,75 +629,3 @@ export default class ValidatorClient {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// One page of a possible multi-page set of mixnodes. The paging interface is quite
|
||||
/// inconvenient, as we don't have the two pieces of information we need to know
|
||||
/// in order to do paging nicely (namely `currentPage` and `totalPages` parameters).
|
||||
///
|
||||
/// Instead, we have only `start_next_page_after`, i.e. the key of the last record
|
||||
/// on this page. In order to get the *next* page, CosmWasm looks at that value,
|
||||
/// finds the next record, and builds the next page starting there. This happens
|
||||
/// **in series** rather than **in parallel** (!).
|
||||
///
|
||||
/// So we have some consistency problems:
|
||||
///
|
||||
/// * we can't make requests at a given block height, so the result set
|
||||
/// which we assemble over time may change while requests are being made.
|
||||
/// * at some point we will make a request for a `start_next_page_after` key
|
||||
/// which has just been deleted from the database.
|
||||
///
|
||||
/// TODO: more robust error handling on the "deleted key" case.
|
||||
export type PagedMixnodeResponse = {
|
||||
nodes: MixNodeBond[],
|
||||
per_page: number, // TODO: camelCase
|
||||
start_next_after: string, // TODO: camelCase
|
||||
}
|
||||
|
||||
// a temporary way of achieving the same paging behaviour for the gateways
|
||||
// the same points made for `PagedResponse` stand here.
|
||||
export type PagedGatewayResponse = {
|
||||
nodes: GatewayBond[],
|
||||
per_page: number, // TODO: camelCase
|
||||
start_next_after: string, // TODO: camelCase
|
||||
}
|
||||
|
||||
export type MixOwnershipResponse = {
|
||||
address: string,
|
||||
has_node: boolean,
|
||||
}
|
||||
|
||||
export type GatewayOwnershipResponse = {
|
||||
address: string,
|
||||
has_gateway: boolean,
|
||||
}
|
||||
|
||||
export type StateParams = {
|
||||
epoch_length: number,
|
||||
// ideally I'd want to define those as `number` rather than `string`, but
|
||||
// rust-side they are defined as Uint128 and Decimal that don't have
|
||||
// native javascript representations and therefore are interpreted as strings after deserialization
|
||||
minimum_mixnode_bond: string,
|
||||
minimum_gateway_bond: string,
|
||||
mixnode_bond_reward_rate: string,
|
||||
gateway_bond_reward_rate: string,
|
||||
mixnode_delegation_reward_rate: string,
|
||||
gateway_delegation_reward_rate: string,
|
||||
mixnode_active_set_size: number,
|
||||
}
|
||||
|
||||
export type Delegation = {
|
||||
owner: string,
|
||||
amount: Coin,
|
||||
}
|
||||
|
||||
export type PagedMixDelegationsResponse = {
|
||||
node_owner: string,
|
||||
delegations: Delegation[],
|
||||
start_next_after: string
|
||||
}
|
||||
|
||||
export type PagedGatewayDelegationsResponse = {
|
||||
node_owner: string,
|
||||
delegations: Delegation[],
|
||||
start_next_after: string
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
PagedGatewayResponse, PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
StateParams
|
||||
} from "./index";
|
||||
} from "./types";
|
||||
import { DirectSecp256k1HdWallet, EncodeObject } from "@cosmjs/proto-signing";
|
||||
import { Coin, StdFee } from "@cosmjs/stargate";
|
||||
import { BroadcastTxResponse } from "@cosmjs/stargate"
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
PagedGatewayResponse, PagedMixDelegationsResponse,
|
||||
PagedMixnodeResponse,
|
||||
StateParams
|
||||
} from "./index";
|
||||
} from "./types";
|
||||
|
||||
export interface IQueryClient {
|
||||
getBalance(address: string, stakeDenom: string): Promise<Coin | null>;
|
||||
|
||||
@@ -1,5 +1,80 @@
|
||||
import { Coin } from "@cosmjs/stargate";
|
||||
|
||||
|
||||
/// One page of a possible multi-page set of mixnodes. The paging interface is quite
|
||||
/// inconvenient, as we don't have the two pieces of information we need to know
|
||||
/// in order to do paging nicely (namely `currentPage` and `totalPages` parameters).
|
||||
///
|
||||
/// Instead, we have only `start_next_page_after`, i.e. the key of the last record
|
||||
/// on this page. In order to get the *next* page, CosmWasm looks at that value,
|
||||
/// finds the next record, and builds the next page starting there. This happens
|
||||
/// **in series** rather than **in parallel** (!).
|
||||
///
|
||||
/// So we have some consistency problems:
|
||||
///
|
||||
/// * we can't make requests at a given block height, so the result set
|
||||
/// which we assemble over time may change while requests are being made.
|
||||
/// * at some point we will make a request for a `start_next_page_after` key
|
||||
/// which has just been deleted from the database.
|
||||
///
|
||||
/// TODO: more robust error handling on the "deleted key" case.
|
||||
export type PagedMixnodeResponse = {
|
||||
nodes: MixNodeBond[],
|
||||
per_page: number, // TODO: camelCase
|
||||
start_next_after: string, // TODO: camelCase
|
||||
}
|
||||
|
||||
// a temporary way of achieving the same paging behaviour for the gateways
|
||||
// the same points made for `PagedResponse` stand here.
|
||||
export type PagedGatewayResponse = {
|
||||
nodes: GatewayBond[],
|
||||
per_page: number, // TODO: camelCase
|
||||
start_next_after: string, // TODO: camelCase
|
||||
}
|
||||
|
||||
export type MixOwnershipResponse = {
|
||||
address: string,
|
||||
has_node: boolean,
|
||||
}
|
||||
|
||||
export type GatewayOwnershipResponse = {
|
||||
address: string,
|
||||
has_gateway: boolean,
|
||||
}
|
||||
|
||||
export type StateParams = {
|
||||
epoch_length: number,
|
||||
// ideally I'd want to define those as `number` rather than `string`, but
|
||||
// rust-side they are defined as Uint128 and Decimal that don't have
|
||||
// native javascript representations and therefore are interpreted as strings after deserialization
|
||||
minimum_mixnode_bond: string,
|
||||
minimum_gateway_bond: string,
|
||||
mixnode_bond_reward_rate: string,
|
||||
gateway_bond_reward_rate: string,
|
||||
mixnode_delegation_reward_rate: string,
|
||||
gateway_delegation_reward_rate: string,
|
||||
mixnode_active_set_size: number,
|
||||
gateway_active_set_size: number,
|
||||
}
|
||||
|
||||
export type Delegation = {
|
||||
owner: string,
|
||||
amount: Coin,
|
||||
}
|
||||
|
||||
export type PagedMixDelegationsResponse = {
|
||||
node_owner: string,
|
||||
delegations: Delegation[],
|
||||
start_next_after: string
|
||||
}
|
||||
|
||||
export type PagedGatewayDelegationsResponse = {
|
||||
node_owner: string,
|
||||
delegations: Delegation[],
|
||||
start_next_after: string
|
||||
}
|
||||
|
||||
|
||||
export enum Layer {
|
||||
Gateway,
|
||||
One,
|
||||
|
||||
@@ -263,12 +263,12 @@ impl NymClient {
|
||||
pub(crate) async fn get_nym_topology(&self) -> NymTopology {
|
||||
let validator_client = validator_client::ApiClient::new(self.validator_server.clone());
|
||||
|
||||
let mixnodes = match validator_client.get_cached_mixnodes().await {
|
||||
let mixnodes = match validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => panic!("{}", err),
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match validator_client.get_cached_gateways().await {
|
||||
let gateways = match validator_client.get_cached_active_gateways().await {
|
||||
Err(err) => panic!("{}", err),
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
use crate::nymd::{
|
||||
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||
};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use mixnet_contract::StateParams;
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
@@ -170,6 +173,13 @@ impl<C> Client<C> {
|
||||
Ok(self.validator_api.get_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn get_state_params(&self) -> Result<StateParams, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_state_params().await?)
|
||||
}
|
||||
|
||||
// basically handles paging for us
|
||||
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
@@ -414,6 +424,18 @@ impl ApiClient {
|
||||
self.validator_api.change_url(new_endpoint);
|
||||
}
|
||||
|
||||
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_active_gateways(
|
||||
&self,
|
||||
) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_active_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnodes().await?)
|
||||
}
|
||||
|
||||
@@ -68,6 +68,16 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
|
||||
self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE])
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_active_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> {
|
||||
self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS, routes::ACTIVE])
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
|
||||
@@ -7,5 +7,7 @@ pub const API_VERSION: &str = VALIDATOR_API_VERSION;
|
||||
pub const MIXNODES: &str = "mixnodes";
|
||||
pub const GATEWAYS: &str = "gateways";
|
||||
|
||||
pub const ACTIVE: &str = "active";
|
||||
|
||||
pub const COCONUT_BLIND_SIGN: &str = "blind_sign";
|
||||
pub const COCONUT_VERIFICATION_KEY: &str = "verification_key";
|
||||
|
||||
@@ -5,12 +5,13 @@ use crate::{IdentityKey, SphinxKey};
|
||||
use cosmwasm_std::{coin, Addr, Coin};
|
||||
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, Serialize, JsonSchema, TS)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema, TS)]
|
||||
pub struct Gateway {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
@@ -60,6 +61,64 @@ impl GatewayBond {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for GatewayBond {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
// first remove invalid cases
|
||||
if self.bond_amount.denom != self.total_delegation.denom {
|
||||
return None;
|
||||
}
|
||||
|
||||
if other.bond_amount.denom != other.total_delegation.denom {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.bond_amount.denom != other.bond_amount.denom {
|
||||
return None;
|
||||
}
|
||||
|
||||
// try to order by total bond + delegation
|
||||
let total_cmp = (self.bond_amount.amount + self.total_delegation.amount)
|
||||
.partial_cmp(&(self.bond_amount.amount + self.total_delegation.amount))?;
|
||||
|
||||
if total_cmp != Ordering::Equal {
|
||||
return Some(total_cmp);
|
||||
}
|
||||
|
||||
// then if those are equal, prefer higher bond over delegation
|
||||
let bond_cmp = self
|
||||
.bond_amount
|
||||
.amount
|
||||
.partial_cmp(&other.bond_amount.amount)?;
|
||||
if bond_cmp != Ordering::Equal {
|
||||
return Some(bond_cmp);
|
||||
}
|
||||
|
||||
// then look at delegation (I'm not sure we can get here, but better safe than sorry)
|
||||
let delegation_cmp = self
|
||||
.total_delegation
|
||||
.amount
|
||||
.partial_cmp(&other.total_delegation.amount)?;
|
||||
if delegation_cmp != Ordering::Equal {
|
||||
return Some(delegation_cmp);
|
||||
}
|
||||
|
||||
// then check block height
|
||||
let height_cmp = self.block_height.partial_cmp(&other.block_height)?;
|
||||
if height_cmp != Ordering::Equal {
|
||||
return Some(height_cmp);
|
||||
}
|
||||
|
||||
// finally go by the rest of the fields in order. It doesn't really matter at this point
|
||||
// but we should be deterministic.
|
||||
let owner_cmp = self.owner.partial_cmp(&other.owner)?;
|
||||
if owner_cmp != Ordering::Equal {
|
||||
return Some(owner_cmp);
|
||||
}
|
||||
|
||||
self.gateway.partial_cmp(&other.gateway)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for GatewayBond {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
@@ -96,3 +155,90 @@ pub struct GatewayOwnershipResponse {
|
||||
pub address: Addr,
|
||||
pub has_gateway: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn gateway_fixture() -> Gateway {
|
||||
Gateway {
|
||||
host: "1.1.1.1".to_string(),
|
||||
mix_port: 123,
|
||||
clients_port: 456,
|
||||
location: "foomplandia".to_string(),
|
||||
sphinx_key: "sphinxkey".to_string(),
|
||||
identity_key: "identitykey".to_string(),
|
||||
version: "0.11.0".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gateway_bond_partial_ord() {
|
||||
let _150foos = Coin::new(150, "foo");
|
||||
let _50foos = Coin::new(50, "foo");
|
||||
let _0foos = Coin::new(0, "foo");
|
||||
|
||||
let gate1 = GatewayBond {
|
||||
bond_amount: _150foos.clone(),
|
||||
total_delegation: _50foos.clone(),
|
||||
owner: Addr::unchecked("foo1"),
|
||||
block_height: 100,
|
||||
gateway: gateway_fixture(),
|
||||
};
|
||||
|
||||
let gate2 = GatewayBond {
|
||||
bond_amount: _150foos.clone(),
|
||||
total_delegation: _50foos.clone(),
|
||||
owner: Addr::unchecked("foo2"),
|
||||
block_height: 120,
|
||||
gateway: gateway_fixture(),
|
||||
};
|
||||
|
||||
let gate3 = GatewayBond {
|
||||
bond_amount: _50foos,
|
||||
total_delegation: _150foos.clone(),
|
||||
owner: Addr::unchecked("foo3"),
|
||||
block_height: 120,
|
||||
gateway: gateway_fixture(),
|
||||
};
|
||||
|
||||
let gate4 = GatewayBond {
|
||||
bond_amount: _150foos.clone(),
|
||||
total_delegation: _0foos.clone(),
|
||||
owner: Addr::unchecked("foo4"),
|
||||
block_height: 120,
|
||||
gateway: gateway_fixture(),
|
||||
};
|
||||
|
||||
let gate5 = GatewayBond {
|
||||
bond_amount: _0foos,
|
||||
total_delegation: _150foos,
|
||||
owner: Addr::unchecked("foo5"),
|
||||
block_height: 120,
|
||||
gateway: gateway_fixture(),
|
||||
};
|
||||
|
||||
// summary:
|
||||
// gate1: 150bond + 50delegation, foo1, 100
|
||||
// gate2: 150bond + 50delegation, foo2, 120
|
||||
// gate3: 50bond + 150delegation, foo3, 120
|
||||
// gate4: 150bond + 0delegation, foo4, 120
|
||||
// gate5: 0bond + 150delegation, foo5, 120
|
||||
|
||||
// highest total bond+delegation is used
|
||||
// then bond followed by delegation
|
||||
// finally just the rest of the fields
|
||||
|
||||
// gate1 has higher total than gate4 or gate5
|
||||
assert!(gate1 > gate4);
|
||||
assert!(gate1 > gate5);
|
||||
|
||||
// gate1 has the same total as gate3, however, gate1 has more tokens in bond
|
||||
assert!(gate1 > gate3);
|
||||
// same case for gate4 and gate5
|
||||
assert!(gate4 > gate5);
|
||||
|
||||
// same bond and delegation, so it's just ordered by height
|
||||
assert!(gate1 < gate2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@ use cosmwasm_std::{coin, Addr, Coin};
|
||||
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, Serialize, JsonSchema, TS)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema, TS)]
|
||||
pub struct MixNode {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
@@ -23,7 +24,9 @@ pub struct MixNode {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize_repr, PartialEq, Deserialize_repr, JsonSchema)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Serialize_repr, PartialEq, PartialOrd, Deserialize_repr, JsonSchema,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum Layer {
|
||||
Gateway = 0,
|
||||
@@ -78,6 +81,69 @@ impl MixNodeBond {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for MixNodeBond {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
// first remove invalid cases
|
||||
if self.bond_amount.denom != self.total_delegation.denom {
|
||||
return None;
|
||||
}
|
||||
|
||||
if other.bond_amount.denom != other.total_delegation.denom {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.bond_amount.denom != other.bond_amount.denom {
|
||||
return None;
|
||||
}
|
||||
|
||||
// try to order by total bond + delegation
|
||||
let total_cmp = (self.bond_amount.amount + self.total_delegation.amount)
|
||||
.partial_cmp(&(self.bond_amount.amount + self.total_delegation.amount))?;
|
||||
|
||||
if total_cmp != Ordering::Equal {
|
||||
return Some(total_cmp);
|
||||
}
|
||||
|
||||
// then if those are equal, prefer higher bond over delegation
|
||||
let bond_cmp = self
|
||||
.bond_amount
|
||||
.amount
|
||||
.partial_cmp(&other.bond_amount.amount)?;
|
||||
if bond_cmp != Ordering::Equal {
|
||||
return Some(bond_cmp);
|
||||
}
|
||||
|
||||
// then look at delegation (I'm not sure we can get here, but better safe than sorry)
|
||||
let delegation_cmp = self
|
||||
.total_delegation
|
||||
.amount
|
||||
.partial_cmp(&other.total_delegation.amount)?;
|
||||
if delegation_cmp != Ordering::Equal {
|
||||
return Some(delegation_cmp);
|
||||
}
|
||||
|
||||
// then check block height
|
||||
let height_cmp = self.block_height.partial_cmp(&other.block_height)?;
|
||||
if height_cmp != Ordering::Equal {
|
||||
return Some(height_cmp);
|
||||
}
|
||||
|
||||
// finally go by the rest of the fields in order. It doesn't really matter at this point
|
||||
// but we should be deterministic.
|
||||
let owner_cmp = self.owner.partial_cmp(&other.owner)?;
|
||||
if owner_cmp != Ordering::Equal {
|
||||
return Some(owner_cmp);
|
||||
}
|
||||
|
||||
let layer_cmp = self.layer.partial_cmp(&other.layer)?;
|
||||
if layer_cmp != Ordering::Equal {
|
||||
return Some(layer_cmp);
|
||||
}
|
||||
|
||||
self.mix_node.partial_cmp(&other.mix_node)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MixNodeBond {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
@@ -114,3 +180,95 @@ pub struct MixOwnershipResponse {
|
||||
pub address: Addr,
|
||||
pub has_node: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn mixnode_fixture() -> MixNode {
|
||||
MixNode {
|
||||
host: "1.1.1.1".to_string(),
|
||||
mix_port: 123,
|
||||
verloc_port: 456,
|
||||
http_api_port: 789,
|
||||
sphinx_key: "sphinxkey".to_string(),
|
||||
identity_key: "identitykey".to_string(),
|
||||
version: "0.11.0".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixnode_bond_partial_ord() {
|
||||
let _150foos = Coin::new(150, "foo");
|
||||
let _50foos = Coin::new(50, "foo");
|
||||
let _0foos = Coin::new(0, "foo");
|
||||
|
||||
let mix1 = MixNodeBond {
|
||||
bond_amount: _150foos.clone(),
|
||||
total_delegation: _50foos.clone(),
|
||||
owner: Addr::unchecked("foo1"),
|
||||
layer: Layer::One,
|
||||
block_height: 100,
|
||||
mix_node: mixnode_fixture(),
|
||||
};
|
||||
|
||||
let mix2 = MixNodeBond {
|
||||
bond_amount: _150foos.clone(),
|
||||
total_delegation: _50foos.clone(),
|
||||
owner: Addr::unchecked("foo2"),
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
};
|
||||
|
||||
let mix3 = MixNodeBond {
|
||||
bond_amount: _50foos,
|
||||
total_delegation: _150foos.clone(),
|
||||
owner: Addr::unchecked("foo3"),
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
};
|
||||
|
||||
let mix4 = MixNodeBond {
|
||||
bond_amount: _150foos.clone(),
|
||||
total_delegation: _0foos.clone(),
|
||||
owner: Addr::unchecked("foo4"),
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
};
|
||||
|
||||
let mix5 = MixNodeBond {
|
||||
bond_amount: _0foos,
|
||||
total_delegation: _150foos,
|
||||
owner: Addr::unchecked("foo5"),
|
||||
layer: Layer::One,
|
||||
block_height: 120,
|
||||
mix_node: mixnode_fixture(),
|
||||
};
|
||||
|
||||
// summary:
|
||||
// mix1: 150bond + 50delegation, foo1, 100
|
||||
// mix2: 150bond + 50delegation, foo2, 120
|
||||
// mix3: 50bond + 150delegation, foo3, 120
|
||||
// mix4: 150bond + 0delegation, foo4, 120
|
||||
// mix5: 0bond + 150delegation, foo5, 120
|
||||
|
||||
// highest total bond+delegation is used
|
||||
// then bond followed by delegation
|
||||
// finally just the rest of the fields
|
||||
|
||||
// mix1 has higher total than mix4 or mix5
|
||||
assert!(mix1 > mix4);
|
||||
assert!(mix1 > mix5);
|
||||
|
||||
// mix1 has the same total as mix3, however, mix1 has more tokens in bond
|
||||
assert!(mix1 > mix3);
|
||||
// same case for mix4 and mix5
|
||||
assert!(mix4 > mix5);
|
||||
|
||||
// same bond and delegation, so it's just ordered by height
|
||||
assert!(mix1 < mix2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ pub struct StateParams {
|
||||
pub mixnode_delegation_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
|
||||
pub gateway_delegation_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
|
||||
pub mixnode_active_set_size: u32,
|
||||
pub gateway_active_set_size: u32,
|
||||
}
|
||||
|
||||
impl Display for StateParams {
|
||||
@@ -67,8 +68,13 @@ impl Display for StateParams {
|
||||
)?;
|
||||
write!(
|
||||
f,
|
||||
"mixnode active set size: {} ]",
|
||||
"mixnode active set size: {}",
|
||||
self.mixnode_active_set_size
|
||||
)?;
|
||||
write!(
|
||||
f,
|
||||
"gateway active set size: {} ]",
|
||||
self.gateway_active_set_size
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+595
-5
@@ -2,6 +2,45 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "Inflector"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ast_node"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93f52ce8fac3d0e6720a92b0576d737c01b1b5db4dd786e962e5925f00bf755"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"swc_macros_common",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
@@ -38,6 +77,12 @@ dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
@@ -50,6 +95,12 @@ version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -178,6 +229,41 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.4.0"
|
||||
@@ -205,6 +291,45 @@ dependencies = [
|
||||
"generic-array 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dprint-core"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93bd44f40b1881477837edc7112695d4b174f058c36c1cbc4c50f8d0482e2ac8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"fnv",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dprint-plugin-typescript"
|
||||
version = "0.43.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ba0077bd2ab9235848e793fbbfb563e6a04b4c8e4149827802a84063c15805"
|
||||
dependencies = [
|
||||
"dprint-core",
|
||||
"dprint-swc-ecma-ast-view",
|
||||
"fnv",
|
||||
"serde",
|
||||
"swc_common",
|
||||
"swc_ecmascript",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dprint-swc-ecma-ast-view"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecf692a2ee5c5f699ed0e95f21686cf6367f3a591e5d8e7bd3041bbf184651f9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"fnv",
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecmascript",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.4"
|
||||
@@ -237,6 +362,12 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.10.4"
|
||||
@@ -253,6 +384,18 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum_kind"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b940da354ae81ef0926c5eaa428207b8f4f091d3956c891dfbd124162bed99"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"swc_macros_common",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
@@ -269,6 +412,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.1"
|
||||
@@ -279,6 +428,27 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "from_variant"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0951635027ca477be98f8774abd6f0345233439d63f307e47101acb40c7cc63d"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"swc_macros_common",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
@@ -304,7 +474,7 @@ version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
@@ -315,7 +485,7 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
]
|
||||
@@ -377,6 +547,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
@@ -388,6 +564,19 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-macro"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a322dd16d960e322c3d92f541b4c1a4f0a2e81e1fdeee430d8cecc8b72e8015f"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
@@ -400,12 +589,18 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "008b0281ca8032567c9711cd48631781c15228301860a39b32deb28d63125e46"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.100"
|
||||
@@ -418,7 +613,7 @@ version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -433,6 +628,12 @@ version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "mixnet-contract"
|
||||
version = "0.1.0"
|
||||
@@ -441,6 +642,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -461,10 +663,54 @@ dependencies = [
|
||||
name = "network-defaults"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"time",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
@@ -477,6 +723,15 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
@@ -526,6 +781,25 @@ dependencies = [
|
||||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.7.5"
|
||||
@@ -536,6 +810,29 @@ dependencies = [
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pmutil"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "precomputed-hash"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
@@ -560,6 +857,30 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
"rand_pcg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
@@ -578,6 +899,41 @@ dependencies = [
|
||||
"getrandom 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
@@ -608,6 +964,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.122"
|
||||
@@ -689,7 +1051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug 0.3.0",
|
||||
@@ -705,6 +1067,18 @@ dependencies = [
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.4.0"
|
||||
@@ -714,18 +1088,206 @@ dependencies = [
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"new_debug_unreachable",
|
||||
"phf_shared",
|
||||
"precomputed-hash",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache_codegen"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_enum"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f584cc881e9e5f1fd6bf827b0444aa94c30d8fe6378cf241071b5f5700b2871f"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"swc_macros_common",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
|
||||
|
||||
[[package]]
|
||||
name = "swc_atoms"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "837a3ef86c2817228e733b6f173c821fd76f9eb21a0bc9001a826be48b00b4e7"
|
||||
dependencies = [
|
||||
"string_cache",
|
||||
"string_cache_codegen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_common"
|
||||
version = "0.10.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c93df65683ec1a001e15ce1de438c7c2c226c0c2462d1cb93fa1bd2a7664170b"
|
||||
dependencies = [
|
||||
"ast_node",
|
||||
"cfg-if 0.1.10",
|
||||
"either",
|
||||
"from_variant",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"owning_ref",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"string_cache",
|
||||
"swc_eq_ignore_macros",
|
||||
"swc_visit",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_ast"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83eb6a73820660a5af3c24ae1d436e84e4d4c13822021140011361e678df247b"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"string_enum",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_parser"
|
||||
version = "0.52.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03250697857164f16fa98f8e1726f566652d13e52ea3f0c3ecea9deb63ee327"
|
||||
dependencies = [
|
||||
"either",
|
||||
"enum_kind",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_visit",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_visit"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3d60b9dc97ae4f181d4d60f43142d8ac9669953db410bcedefb29a14627e19"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
"swc_visit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecmascript"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ffb53afe008c15d4dc4957e80148c4b457659f93e4d4e8736eaeae352e48ec8"
|
||||
dependencies = [
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_eq_ignore_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c8f200a2eaed938e7c1a685faaa66e6d42fa9e17da5f62572d3cbc335898f5e"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_macros_common"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08ed2e930f5a1a4071fe62c90fd3a296f6030e5d94bfe13993244423caf59a78"
|
||||
dependencies = [
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_visit"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a423caa0b4585118164dbad8f1ad52b592a9a9370b25decc4d84c6b4309132c0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"swc_visit_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_visit_macros"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b2825fee79f10d0166e8e650e79c7a862fb991db275743083f07555d7641f0"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"swc_macros_common",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.65"
|
||||
@@ -797,6 +1359,28 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ts-rs"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "369e48de67506679b3a576b0faf666fa9f9acf2fd00b4c61e28bdb6c8e08ec06"
|
||||
dependencies = [
|
||||
"dprint-plugin-typescript",
|
||||
"ts-rs-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ts-rs-macros"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f269e8fd28e26b4cdbd01f81f345aaf666131511e54a735a76a614b5062d0a5a"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.13.0"
|
||||
@@ -839,6 +1423,12 @@ dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
|
||||
@@ -10,9 +10,9 @@ use cosmwasm_std::{
|
||||
entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, QueryResponse,
|
||||
Response, Uint128,
|
||||
};
|
||||
use mixnet_contract::{
|
||||
ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, RawDelegationData, StateParams,
|
||||
};
|
||||
use cosmwasm_storage::singleton_read;
|
||||
use mixnet_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, StateParams};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const INITIAL_DEFAULT_EPOCH_LENGTH: u32 = 2;
|
||||
|
||||
@@ -29,6 +29,7 @@ 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_GATEWAY_ACTIVE_SET_SIZE: u32 = 20;
|
||||
|
||||
fn default_initial_state(owner: Addr) -> State {
|
||||
let mixnode_bond_reward_rate = Decimal::percent(INITIAL_MIXNODE_BOND_REWARD_RATE);
|
||||
@@ -48,6 +49,7 @@ fn default_initial_state(owner: Addr) -> State {
|
||||
mixnode_delegation_reward_rate,
|
||||
gateway_delegation_reward_rate,
|
||||
mixnode_active_set_size: INITIAL_MIXNODE_ACTIVE_SET_SIZE,
|
||||
gateway_active_set_size: INITIAL_GATEWAY_ACTIVE_SET_SIZE,
|
||||
},
|
||||
mixnode_epoch_bond_reward: calculate_epoch_reward_rate(
|
||||
INITIAL_DEFAULT_EPOCH_LENGTH,
|
||||
@@ -207,69 +209,54 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(mut deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
use crate::storage::{
|
||||
gateway_delegations, gateway_delegations_read, gateway_delegations_read_old, gateways_read,
|
||||
mix_delegations, mix_delegations_read, mix_delegations_read_old, mixnodes_read,
|
||||
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldStateParams {
|
||||
epoch_length: u32,
|
||||
minimum_mixnode_bond: Uint128,
|
||||
minimum_gateway_bond: Uint128,
|
||||
mixnode_bond_reward_rate: Decimal,
|
||||
gateway_bond_reward_rate: Decimal,
|
||||
mixnode_delegation_reward_rate: Decimal,
|
||||
gateway_delegation_reward_rate: Decimal,
|
||||
mixnode_active_set_size: u32,
|
||||
}
|
||||
|
||||
// adding gateways active set
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldState {
|
||||
owner: Addr,
|
||||
network_monitor_address: Addr,
|
||||
params: OldStateParams,
|
||||
mixnode_epoch_bond_reward: Decimal,
|
||||
gateway_epoch_bond_reward: Decimal,
|
||||
mixnode_epoch_delegation_reward: Decimal,
|
||||
gateway_epoch_delegation_reward: Decimal,
|
||||
}
|
||||
|
||||
let old_state: OldState = singleton_read(deps.storage, b"config").load()?;
|
||||
|
||||
let new_state = State {
|
||||
owner: old_state.owner,
|
||||
network_monitor_address: old_state.network_monitor_address,
|
||||
params: StateParams {
|
||||
epoch_length: old_state.params.epoch_length,
|
||||
minimum_mixnode_bond: old_state.params.minimum_mixnode_bond,
|
||||
minimum_gateway_bond: old_state.params.minimum_gateway_bond,
|
||||
mixnode_bond_reward_rate: old_state.params.mixnode_bond_reward_rate,
|
||||
gateway_bond_reward_rate: old_state.params.gateway_bond_reward_rate,
|
||||
mixnode_delegation_reward_rate: old_state.params.mixnode_delegation_reward_rate,
|
||||
gateway_delegation_reward_rate: old_state.params.gateway_delegation_reward_rate,
|
||||
mixnode_active_set_size: old_state.params.mixnode_active_set_size,
|
||||
gateway_active_set_size: INITIAL_GATEWAY_ACTIVE_SET_SIZE,
|
||||
},
|
||||
mixnode_epoch_bond_reward: old_state.mixnode_epoch_bond_reward,
|
||||
gateway_epoch_bond_reward: old_state.gateway_epoch_bond_reward,
|
||||
mixnode_epoch_delegation_reward: old_state.mixnode_epoch_delegation_reward,
|
||||
gateway_epoch_delegation_reward: old_state.gateway_epoch_delegation_reward,
|
||||
};
|
||||
use crate::transactions::delegations;
|
||||
use cosmwasm_std::{Order, StdResult};
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
|
||||
// Read existing delegations data, drop invalid values, and rewrite delegations data with valid data only
|
||||
fn overwrite_mixnode_delegations_data(
|
||||
identity: &str,
|
||||
deps: &mut DepsMut,
|
||||
) -> Result<(), ContractError> {
|
||||
let delegations_bucket = mix_delegations_read(deps.storage, identity);
|
||||
let old_delegations_bucket = mix_delegations_read_old(deps.storage, identity);
|
||||
let mut delegations_vec = delegations(delegations_bucket)?;
|
||||
let old_delegations = delegations::<Uint128>(old_delegations_bucket)?;
|
||||
for delegation in old_delegations {
|
||||
delegations_vec.push((delegation.0, RawDelegationData::new(delegation.1, 1)))
|
||||
}
|
||||
|
||||
for (key, delegation) in delegations_vec {
|
||||
mix_delegations(deps.storage, identity).save(&key, &delegation)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn overwrite_gateway_delegations_data(
|
||||
identity: &str,
|
||||
deps: &mut DepsMut,
|
||||
) -> Result<(), ContractError> {
|
||||
let delegations_bucket = gateway_delegations_read(deps.storage, identity);
|
||||
let old_delegations_bucket = gateway_delegations_read_old(deps.storage, identity);
|
||||
let mut delegations_vec = delegations(delegations_bucket)?;
|
||||
let old_delegations = delegations::<Uint128>(old_delegations_bucket)?;
|
||||
for delegation in old_delegations {
|
||||
delegations_vec.push((delegation.0, RawDelegationData::new(delegation.1, 1)))
|
||||
}
|
||||
|
||||
for (key, delegation) in delegations_vec {
|
||||
gateway_delegations(deps.storage, identity).save(&key, &delegation)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mixnet_bonds = mixnodes_read(deps.storage)
|
||||
.range(None, None, Order::Ascending)
|
||||
.map(|res| res.map(|item| item.1))
|
||||
.collect::<StdResult<Vec<MixNodeBond>>>()?;
|
||||
|
||||
for bond in mixnet_bonds {
|
||||
overwrite_mixnode_delegations_data(bond.identity(), &mut deps)?;
|
||||
}
|
||||
|
||||
let gateway_bonds = gateways_read(deps.storage)
|
||||
.range(None, None, Order::Ascending)
|
||||
.map(|res| res.map(|item| item.1))
|
||||
.collect::<StdResult<Vec<GatewayBond>>>()?;
|
||||
|
||||
for bond in gateway_bonds {
|
||||
overwrite_gateway_delegations_data(bond.identity(), &mut deps)?;
|
||||
}
|
||||
config(deps.storage).save(&new_state)?;
|
||||
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
@@ -643,6 +643,7 @@ mod tests {
|
||||
mixnode_delegation_reward_rate: "7.89".parse().unwrap(),
|
||||
gateway_delegation_reward_rate: "0.12".parse().unwrap(),
|
||||
mixnode_active_set_size: 1000,
|
||||
gateway_active_set_size: 20,
|
||||
},
|
||||
mixnode_epoch_bond_reward: "1.23".parse().unwrap(),
|
||||
gateway_epoch_bond_reward: "4.56".parse().unwrap(),
|
||||
|
||||
@@ -318,14 +318,6 @@ pub fn mix_delegations_read<'a>(
|
||||
ReadonlyBucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()])
|
||||
}
|
||||
|
||||
// https://github.com/nymtech/nym/blob/122f5d9f2e5c1ced96e3b9ba0c74ef8b7dbde2c7/contracts/mixnet/src/storage.rs
|
||||
pub fn mix_delegations_read_old<'a>(
|
||||
storage: &'a dyn Storage,
|
||||
mix_identity: IdentityKeyRef,
|
||||
) -> ReadonlyBucket<'a, Uint128> {
|
||||
ReadonlyBucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()])
|
||||
}
|
||||
|
||||
pub fn reverse_mix_delegations<'a>(storage: &'a mut dyn Storage, owner: &Addr) -> Bucket<'a, ()> {
|
||||
Bucket::multilevel(storage, &[PREFIX_REVERSE_MIX_DELEGATION, owner.as_bytes()])
|
||||
}
|
||||
@@ -357,16 +349,6 @@ pub fn gateway_delegations_read<'a>(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn gateway_delegations_read_old<'a>(
|
||||
storage: &'a dyn Storage,
|
||||
gateway_identity: IdentityKeyRef,
|
||||
) -> ReadonlyBucket<'a, Uint128> {
|
||||
ReadonlyBucket::multilevel(
|
||||
storage,
|
||||
&[PREFIX_GATEWAY_DELEGATION, gateway_identity.as_bytes()],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn reverse_gateway_delegations<'a>(
|
||||
storage: &'a mut dyn Storage,
|
||||
owner: &Addr,
|
||||
|
||||
@@ -1658,6 +1658,7 @@ pub mod tests {
|
||||
INITIAL_GATEWAY_DELEGATION_REWARD_RATE,
|
||||
),
|
||||
mixnode_active_set_size: 42, // change something
|
||||
gateway_active_set_size: 5,
|
||||
};
|
||||
|
||||
// cannot be updated from non-owner account
|
||||
|
||||
@@ -20,6 +20,7 @@ pub struct TauriStateParams {
|
||||
mixnode_delegation_reward_rate: String,
|
||||
gateway_delegation_reward_rate: String,
|
||||
mixnode_active_set_size: u32,
|
||||
gateway_active_set_size: u32,
|
||||
}
|
||||
|
||||
impl From<StateParams> for TauriStateParams {
|
||||
@@ -33,6 +34,7 @@ impl From<StateParams> for TauriStateParams {
|
||||
mixnode_delegation_reward_rate: p.mixnode_delegation_reward_rate.to_string(),
|
||||
gateway_delegation_reward_rate: p.gateway_delegation_reward_rate.to_string(),
|
||||
mixnode_active_set_size: p.mixnode_active_set_size,
|
||||
gateway_active_set_size: p.gateway_active_set_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +52,7 @@ impl TryFrom<TauriStateParams> for StateParams {
|
||||
mixnode_delegation_reward_rate: Decimal::from_str(p.mixnode_delegation_reward_rate.as_str())?,
|
||||
gateway_delegation_reward_rate: Decimal::from_str(p.gateway_delegation_reward_rate.as_str())?,
|
||||
mixnode_active_set_size: p.mixnode_active_set_size,
|
||||
gateway_active_set_size: p.gateway_active_set_size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ export interface TauriStateParams {
|
||||
mixnode_delegation_reward_rate: string;
|
||||
gateway_delegation_reward_rate: string;
|
||||
mixnode_active_set_size: number;
|
||||
gateway_active_set_size: number;
|
||||
}
|
||||
Vendored
+150
-5
@@ -4,10 +4,10 @@
|
||||
use crate::nymd_client::Client;
|
||||
use anyhow::Result;
|
||||
use config::defaults::VALIDATOR_API_VERSION;
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond, StateParams};
|
||||
use rocket::fairing::AdHoc;
|
||||
use serde::Serialize;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use tokio::sync::RwLock;
|
||||
@@ -31,6 +31,12 @@ struct ValidatorCacheInner {
|
||||
initialised: AtomicBool,
|
||||
mixnodes: RwLock<Cache<Vec<MixNodeBond>>>,
|
||||
gateways: RwLock<Cache<Vec<GatewayBond>>>,
|
||||
|
||||
active_mixnodes_available: AtomicBool,
|
||||
active_gateways_available: AtomicBool,
|
||||
|
||||
current_mixnode_active_set_size: AtomicUsize,
|
||||
current_gateway_active_set_size: AtomicUsize,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Clone)]
|
||||
@@ -75,13 +81,17 @@ impl<C> ValidatorCacheRefresher<C> {
|
||||
self.nymd_client.get_gateways()
|
||||
)?;
|
||||
|
||||
let state_params = self.nymd_client.get_state_params().await?;
|
||||
|
||||
info!(
|
||||
"Updating validator cache. There are {} mixnodes and {} gateways",
|
||||
mixnodes.len(),
|
||||
gateways.len()
|
||||
);
|
||||
|
||||
self.cache.update_cache(mixnodes, gateways).await;
|
||||
self.cache
|
||||
.update_cache(mixnodes, gateways, state_params)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -117,12 +127,95 @@ impl ValidatorCache {
|
||||
rocket.manage(Self::new()).mount(
|
||||
// this format! is so ugly...
|
||||
format!("/{}", VALIDATOR_API_VERSION),
|
||||
routes![routes::get_mixnodes, routes::get_gateways],
|
||||
routes![
|
||||
routes::get_mixnodes,
|
||||
routes::get_gateways,
|
||||
routes::get_active_mixnodes,
|
||||
routes::get_active_gateways
|
||||
],
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async fn update_cache(&self, mixnodes: Vec<MixNodeBond>, gateways: Vec<GatewayBond>) {
|
||||
// TODO: check if all nodes can be compared together,
|
||||
// i.e. they all have the same denom for bonds and delegations
|
||||
fn verify_mixnodes(&self, mixnodes: &[MixNodeBond]) -> bool {
|
||||
if mixnodes.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let expected_denom = &mixnodes[0].bond_amount.denom;
|
||||
for mixnode in mixnodes {
|
||||
if &mixnode.bond_amount.denom != expected_denom
|
||||
|| &mixnode.total_delegation.denom != expected_denom
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// TODO: check if all nodes can be compared together,
|
||||
// i.e. they all have the same denom for bonds and delegations
|
||||
fn verify_gateways(&self, gateways: &[GatewayBond]) -> bool {
|
||||
if gateways.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let expected_denom = &gateways[0].bond_amount.denom;
|
||||
for gateway in gateways {
|
||||
if &gateway.bond_amount.denom != expected_denom
|
||||
|| &gateway.total_delegation.denom != expected_denom
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
async fn update_cache(
|
||||
&self,
|
||||
mut mixnodes: Vec<MixNodeBond>,
|
||||
mut gateways: Vec<GatewayBond>,
|
||||
state: StateParams,
|
||||
) {
|
||||
// if our data is valid, it means the active sets are available,
|
||||
// otherwise we must explicitly indicate nobody can read this data
|
||||
|
||||
if self.verify_mixnodes(&mixnodes) {
|
||||
// partial_cmp can only fail if the nodes have different denomination,
|
||||
// but we just checked for that hence the unwraps are fine here
|
||||
// Note the reverse order of comparison so that the "highest" node would be first
|
||||
mixnodes.sort_by(|a, b| b.partial_cmp(a).unwrap());
|
||||
self.inner
|
||||
.active_mixnodes_available
|
||||
.store(true, Ordering::SeqCst);
|
||||
self.inner
|
||||
.current_mixnode_active_set_size
|
||||
.store(state.mixnode_active_set_size as usize, Ordering::SeqCst);
|
||||
} else {
|
||||
self.inner
|
||||
.active_mixnodes_available
|
||||
.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if self.verify_gateways(&gateways) {
|
||||
// partial_cmp can only fail if the nodes have different denomination,
|
||||
// but we just checked for that hence the unwraps are fine here
|
||||
// Note the reverse order of comparison so that the "highest" node would be first
|
||||
gateways.sort_by(|a, b| b.partial_cmp(a).unwrap());
|
||||
self.inner
|
||||
.active_gateways_available
|
||||
.store(true, Ordering::SeqCst);
|
||||
self.inner
|
||||
.current_gateway_active_set_size
|
||||
.store(state.gateway_active_set_size as usize, Ordering::SeqCst);
|
||||
} else {
|
||||
self.inner
|
||||
.active_gateways_available
|
||||
.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
self.inner.mixnodes.write().await.set(mixnodes);
|
||||
self.inner.gateways.write().await.set(gateways);
|
||||
}
|
||||
@@ -135,6 +228,54 @@ impl ValidatorCache {
|
||||
self.inner.gateways.read().await.clone()
|
||||
}
|
||||
|
||||
pub async fn active_mixnodes(&self) -> Option<Cache<Vec<MixNodeBond>>> {
|
||||
// if active set is available, it means it is already sorted
|
||||
if self.inner.active_mixnodes_available.load(Ordering::SeqCst) {
|
||||
let cache = self.inner.mixnodes.read().await;
|
||||
let timestamp = cache.as_at;
|
||||
let nodes = cache
|
||||
.value
|
||||
.iter()
|
||||
.take(
|
||||
self.inner
|
||||
.current_mixnode_active_set_size
|
||||
.load(Ordering::SeqCst),
|
||||
)
|
||||
.cloned()
|
||||
.collect();
|
||||
Some(Cache {
|
||||
value: nodes,
|
||||
as_at: timestamp,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn active_gateways(&self) -> Option<Cache<Vec<GatewayBond>>> {
|
||||
// if active set is available, it means it is already sorted
|
||||
if self.inner.active_gateways_available.load(Ordering::SeqCst) {
|
||||
let cache = self.inner.gateways.read().await;
|
||||
let timestamp = cache.as_at;
|
||||
let nodes = cache
|
||||
.value
|
||||
.iter()
|
||||
.take(
|
||||
self.inner
|
||||
.current_gateway_active_set_size
|
||||
.load(Ordering::SeqCst),
|
||||
)
|
||||
.cloned()
|
||||
.collect();
|
||||
Some(Cache {
|
||||
value: nodes,
|
||||
as_at: timestamp,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialised(&self) -> bool {
|
||||
self.inner.initialised.load(Ordering::Relaxed)
|
||||
}
|
||||
@@ -158,6 +299,10 @@ impl ValidatorCacheInner {
|
||||
initialised: AtomicBool::new(false),
|
||||
mixnodes: RwLock::new(Cache::default()),
|
||||
gateways: RwLock::new(Cache::default()),
|
||||
active_mixnodes_available: AtomicBool::new(false),
|
||||
active_gateways_available: AtomicBool::new(false),
|
||||
current_mixnode_active_set_size: Default::default(),
|
||||
current_gateway_active_set_size: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+14
@@ -15,3 +15,17 @@ pub(crate) async fn get_mixnodes(cache: &State<ValidatorCache>) -> Json<Vec<MixN
|
||||
pub(crate) async fn get_gateways(cache: &State<ValidatorCache>) -> Json<Vec<GatewayBond>> {
|
||||
Json(cache.gateways().await.value)
|
||||
}
|
||||
|
||||
#[get("/mixnodes/active")]
|
||||
pub(crate) async fn get_active_mixnodes(
|
||||
cache: &State<ValidatorCache>,
|
||||
) -> Option<Json<Vec<MixNodeBond>>> {
|
||||
cache.active_mixnodes().await.map(|cache| Json(cache.value))
|
||||
}
|
||||
|
||||
#[get("/gateways/active")]
|
||||
pub(crate) async fn get_active_gateways(
|
||||
cache: &State<ValidatorCache>,
|
||||
) -> Option<Json<Vec<GatewayBond>>> {
|
||||
cache.active_gateways().await.map(|cache| Json(cache.value))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::rewarding::{
|
||||
PER_MIXNODE_DELEGATION_GAS_INCREASE, REWARDING_GAS_LIMIT_MULTIPLIER,
|
||||
};
|
||||
use config::defaults::DEFAULT_VALIDATOR_API_PORT;
|
||||
use mixnet_contract::{Delegation, ExecuteMsg, GatewayBond, IdentityKey, MixNodeBond};
|
||||
use mixnet_contract::{Delegation, ExecuteMsg, GatewayBond, IdentityKey, MixNodeBond, StateParams};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use validator_client::nymd::{
|
||||
@@ -106,6 +106,13 @@ impl<C> Client<C> {
|
||||
self.0.read().await.get_all_nymd_gateways().await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_state_params(&self) -> Result<StateParams, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
self.0.read().await.get_state_params().await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_mixnode_delegations(
|
||||
&self,
|
||||
identity: IdentityKey,
|
||||
|
||||
@@ -170,7 +170,7 @@ impl Rewarder {
|
||||
|
||||
/// Queries the smart contract in order to obtain the current list of bonded mixnodes and then
|
||||
/// for each mixnode determines how many delegators it has.
|
||||
async fn produce_mixnode_delegators_map(
|
||||
async fn produce_active_mixnode_delegators_map(
|
||||
&self,
|
||||
) -> Result<HashMap<IdentityKey, usize>, RewardingError> {
|
||||
// Technically we could optimise it by creating a concurrent stream and executing multiple
|
||||
@@ -189,8 +189,13 @@ impl Rewarder {
|
||||
// instantaneous.
|
||||
let mut map = HashMap::new();
|
||||
|
||||
let bonded_mixnodes = self.validator_cache.mixnodes().await.into_inner();
|
||||
for mix in bonded_mixnodes.into_iter() {
|
||||
let active_bonded_mixnodes = self
|
||||
.validator_cache
|
||||
.active_mixnodes()
|
||||
.await
|
||||
.ok_or(RewardingError::NoMixnodesToReward)?
|
||||
.into_inner();
|
||||
for mix in active_bonded_mixnodes.into_iter() {
|
||||
let delegator_count = self
|
||||
.get_mixnode_delegators_count(mix.mix_node.identity_key.clone())
|
||||
.await?;
|
||||
@@ -202,14 +207,19 @@ impl Rewarder {
|
||||
|
||||
/// Queries the smart contract in order to obtain the current list of bonded gateways and then
|
||||
/// for each gateway determines how many delegators it has.
|
||||
async fn produce_gateway_delegators_map(
|
||||
async fn produce_active_gateway_delegators_map(
|
||||
&self,
|
||||
) -> Result<HashMap<IdentityKey, usize>, RewardingError> {
|
||||
// look at comments in `produce_mixnode_delegators_map` for some optimisation elaboration
|
||||
let mut map = HashMap::new();
|
||||
|
||||
let bonded_gateways = self.validator_cache.gateways().await.into_inner();
|
||||
for gateway in bonded_gateways.into_iter() {
|
||||
let active_bonded_gateways = self
|
||||
.validator_cache
|
||||
.active_gateways()
|
||||
.await
|
||||
.ok_or(RewardingError::NoGatewaysToReward)?
|
||||
.into_inner();
|
||||
for gateway in active_bonded_gateways.into_iter() {
|
||||
let delegator_count = self
|
||||
.get_gateway_delegators_count(gateway.gateway.identity_key.clone())
|
||||
.await?;
|
||||
@@ -237,8 +247,8 @@ impl Rewarder {
|
||||
/// Given the list of mixnodes that were tested in the last epoch, tries to determine the
|
||||
/// subset that are eligible for any rewards.
|
||||
///
|
||||
/// As of right now, it is a rather straightforward process. It is only checked whether the node
|
||||
/// is currently bonded and has uptime > 0.
|
||||
/// As of right now, it is a rather straightforward process. It is checked whether the node
|
||||
/// is currently bonded, has uptime > 0 and is part of the "active" set.
|
||||
/// Unlike the typescript rewards script, it currently does not look at the verloc data nor
|
||||
/// whether the non-mixing ports are open.
|
||||
///
|
||||
@@ -259,10 +269,10 @@ impl Rewarder {
|
||||
// and the lack of port data / verloc data will eventually be balanced out anyway
|
||||
// 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_mixnode_delegators_map().await?;
|
||||
let mixnode_delegators = self.produce_active_mixnode_delegators_map().await?;
|
||||
|
||||
// 1. go through all active mixnodes
|
||||
// 2. filter out nodes that are currently not bonded (as `mixnode_delegators` was obtained by
|
||||
// 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
|
||||
@@ -286,8 +296,8 @@ impl Rewarder {
|
||||
/// Given the list of gateways that were tested in the last epoch, tries to determine the
|
||||
/// subset that are eligible for any rewards.
|
||||
///
|
||||
/// As of right now, it is a rather straightforward process. It is only checked whether the node
|
||||
/// is currently bonded and has uptime > 0.
|
||||
/// As of right now, it is a rather straightforward process. It is checked whether the node
|
||||
/// is currently bonded, has uptime > 0 and is part of the "active" set.
|
||||
/// Unlike the typescript rewards script, it currently does not look at the non-mixing ports are open.
|
||||
///
|
||||
/// The method also obtains the number of delegators towards the node in order to more accurately
|
||||
@@ -301,7 +311,7 @@ impl Rewarder {
|
||||
&self,
|
||||
active_gateways: &[GatewayStatusReport],
|
||||
) -> Result<Vec<GatewayToReward>, RewardingError> {
|
||||
let gateway_delegators = self.produce_gateway_delegators_map().await?;
|
||||
let gateway_delegators = self.produce_active_gateway_delegators_map().await?;
|
||||
|
||||
let eligible_nodes = active_gateways
|
||||
.iter()
|
||||
@@ -329,7 +339,7 @@ impl Rewarder {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `epoch`: the specified epoch.
|
||||
async fn get_active_nodes(
|
||||
async fn get_active_monitor_nodes(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
) -> Result<(Vec<MixnodeStatusReport>, Vec<GatewayStatusReport>), RewardingError> {
|
||||
@@ -450,25 +460,29 @@ impl Rewarder {
|
||||
///
|
||||
/// * `epoch_rewarding_id`: id of the current epoch rewarding.
|
||||
///
|
||||
/// * `active_mixnodes`: list of the nodes that were tested at least once by the network monitor
|
||||
/// in the last epoch.
|
||||
/// * `active_monitor_mixnodes`: list of the nodes that were tested at least once by the network monitor
|
||||
/// in the last epoch.
|
||||
///
|
||||
/// * `active_gateways`: list of the nodes that were tested at least once by the network monitor
|
||||
/// in the last epoch.
|
||||
/// * `active_monitor_gateways`: list of the nodes that were tested at least once by the network monitor
|
||||
/// in the last epoch.
|
||||
async fn distribute_rewards(
|
||||
&self,
|
||||
epoch_rewarding_id: i64,
|
||||
active_mixnodes: &[MixnodeStatusReport],
|
||||
active_gateways: &[GatewayStatusReport],
|
||||
active_monitor_mixnodes: &[MixnodeStatusReport],
|
||||
active_monitor_gateways: &[GatewayStatusReport],
|
||||
) -> Result<(RewardingReport, Option<FailureData>), RewardingError> {
|
||||
let mut failure_data = FailureData::default();
|
||||
|
||||
let eligible_mixnodes = self.determine_eligible_mixnodes(active_mixnodes).await?;
|
||||
let eligible_mixnodes = self
|
||||
.determine_eligible_mixnodes(active_monitor_mixnodes)
|
||||
.await?;
|
||||
if eligible_mixnodes.is_empty() {
|
||||
return Err(RewardingError::NoMixnodesToReward);
|
||||
}
|
||||
|
||||
let eligible_gateways = self.determine_eligible_gateways(active_gateways).await?;
|
||||
let eligible_gateways = self
|
||||
.determine_eligible_gateways(active_monitor_gateways)
|
||||
.await?;
|
||||
if eligible_gateways.is_empty() {
|
||||
return Err(RewardingError::NoGatewaysToReward);
|
||||
}
|
||||
@@ -718,7 +732,8 @@ impl Rewarder {
|
||||
);
|
||||
|
||||
// get nodes that were active during the epoch
|
||||
let (active_mixnodes, active_gateways) = self.get_active_nodes(epoch).await?;
|
||||
let (active_monitor_mixnodes, active_monitor_gateways) =
|
||||
self.get_active_monitor_nodes(epoch).await?;
|
||||
|
||||
// insert information about beginning the procedure (so that if we crash during it,
|
||||
// we wouldn't attempt to possibly double reward operators)
|
||||
@@ -728,7 +743,11 @@ impl Rewarder {
|
||||
.await?;
|
||||
|
||||
let (report, failure_data) = self
|
||||
.distribute_rewards(epoch_rewarding_id, &active_mixnodes, &active_gateways)
|
||||
.distribute_rewards(
|
||||
epoch_rewarding_id,
|
||||
&active_monitor_mixnodes,
|
||||
&active_monitor_gateways,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.storage
|
||||
@@ -764,7 +783,11 @@ impl Rewarder {
|
||||
"Updating historical daily uptimes of all nodes and purging old status reports..."
|
||||
);
|
||||
self.storage
|
||||
.update_historical_uptimes(&epoch_iso_8601, &active_mixnodes, &active_gateways)
|
||||
.update_historical_uptimes(
|
||||
&epoch_iso_8601,
|
||||
&active_monitor_mixnodes,
|
||||
&active_monitor_gateways,
|
||||
)
|
||||
.await?;
|
||||
self.storage.purge_old_statuses(two_days_ago).await?;
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ impl NodeStatusStorage {
|
||||
Ok(run_count as usize)
|
||||
}
|
||||
|
||||
/// Given lists of reports of all active mixnodes and gateways, inserts the data into the
|
||||
/// Given lists of reports of all monitor-active mixnodes and gateways, inserts the data into the
|
||||
/// historical uptime tables.
|
||||
///
|
||||
/// This method is called at every reward cycle. Note that currently to work as expected, it
|
||||
@@ -453,8 +453,8 @@ impl NodeStatusStorage {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `today_iso_8601`: today's date expressed in ISO 8601, i.e. YYYY-MM-DD
|
||||
/// * `mixnode_reports`: slice of reports for all active mixnodes
|
||||
/// * `gateway_reports`: slice of reports for all active gateways
|
||||
/// * `mixnode_reports`: slice of reports for all monitor-active mixnodes
|
||||
/// * `gateway_reports`: slice of reports for all monitor-active gateways
|
||||
pub(crate) async fn update_historical_uptimes(
|
||||
&self,
|
||||
today_iso_8601: &str,
|
||||
|
||||
@@ -102,13 +102,23 @@ export default function AdminForm(props: AdminFormProps) {
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
required
|
||||
id="active_set"
|
||||
name="active_set"
|
||||
id="mixnode_active_set"
|
||||
name="mixnode_active_set"
|
||||
label="Mixnode Active Set Size"
|
||||
defaultValue={props.currentParams.mixnode_active_set_size}
|
||||
fullWidth
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
required
|
||||
id="gateway_active_set"
|
||||
name="gateway_active_set"
|
||||
label="Gateway Active Set Size"
|
||||
defaultValue={props.currentParams.gateway_active_set_size}
|
||||
fullWidth
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<div className={classes.buttons}>
|
||||
<Button
|
||||
|
||||
Vendored
+4
@@ -1,2 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"@material-ui/core": "^4.11.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"@nymproject/nym-validator-client": "0.17.0",
|
||||
"@nymproject/nym-validator-client": "0.18.0",
|
||||
"@types/react-dom": "^17.0.3",
|
||||
"bs58": "^4.0.1",
|
||||
"next": "11.1.1",
|
||||
|
||||
@@ -84,7 +84,8 @@ export default function Admin() {
|
||||
mixnode_delegation_reward_rate: event.target.mix_delegation_reward.value,
|
||||
gateway_delegation_reward_rate: event.target.gateway_delegation_reward.value,
|
||||
epoch_length: parseInt(event.target.epoch_length.value),
|
||||
mixnode_active_set_size: parseInt(event.target.active_set.value),
|
||||
mixnode_active_set_size: parseInt(event.target.mixnode_active_set.value),
|
||||
gateway_active_set_size: parseInt(event.target.gateway_active_set.value),
|
||||
};
|
||||
setUpdatingState(true)
|
||||
await client.updateStateParams(newState)
|
||||
|
||||
@@ -1356,9 +1356,10 @@
|
||||
dependencies:
|
||||
"@napi-rs/triples" "^1.0.3"
|
||||
|
||||
"@nymproject/nym-validator-client@0.17.0":
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@nymproject/nym-validator-client/-/nym-validator-client-0.17.0.tgz#b03af24295cbd2f1b94ffd0c38c5a493e994d111"
|
||||
"@nymproject/nym-validator-client@0.18.0":
|
||||
version "0.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@nymproject/nym-validator-client/-/nym-validator-client-0.18.0.tgz#4dd72bafdf6c72b603242f32c0bb9a1f9e475b98"
|
||||
integrity sha512-FO1T15S2BJVuMoPA2yOaH40aD3hKJPKJVyX5ix7eJEbBWIdsYNoVeVc/soHhaAU1FIy2uU0G/FZQkaUYJGGb7Q==
|
||||
dependencies:
|
||||
"@cosmjs/cosmwasm-stargate" "^0.25.5"
|
||||
"@cosmjs/math" "^0.25.5"
|
||||
|
||||
Reference in New Issue
Block a user