Merge remote-tracking branch 'origin/develop' into feature/hrycyszynvpn
This commit is contained in:
@@ -11,6 +11,9 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
|
||||
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||
- mixnet-contrat: Added staking_supply field to ContractStateParams.
|
||||
- network-explorer-ui: Upgrade to React Router 6
|
||||
- rewarding: replace circulating supply with staking supply in reward calculations ([#1324])
|
||||
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
|
||||
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation.
|
||||
- validator-api: add Swagger to document the REST API ([#1249]).
|
||||
@@ -24,6 +27,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- wallet: new delegation and rewards UI
|
||||
- wallet: show version in nav bar
|
||||
- wallet: contract admin route put back
|
||||
- waller: staking_supply field to StateParams
|
||||
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
|
||||
|
||||
### Fixed
|
||||
@@ -37,6 +41,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- mixnode: the mixnode learned how to shutdown gracefully.
|
||||
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
|
||||
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
|
||||
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -60,7 +65,9 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#1302]: https://github.com/nymtech/nym/pull/1302
|
||||
[#1318]: https://github.com/nymtech/nym/pull/1318
|
||||
[#1322]: https://github.com/nymtech/nym/pull/1322
|
||||
[#1324]: https://github.com/nymtech/nym/pull/1324
|
||||
[#1328]: https://github.com/nymtech/nym/pull/1328
|
||||
[#1329]: https://github.com/nymtech/nym/pull/1329
|
||||
|
||||
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
|
||||
|
||||
|
||||
Generated
+1
@@ -2852,6 +2852,7 @@ dependencies = [
|
||||
"nymsphinx-types",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"task",
|
||||
"tokio",
|
||||
"tokio-util 0.7.3",
|
||||
"url",
|
||||
|
||||
@@ -220,9 +220,9 @@ impl DelegatorRewardParams {
|
||||
|
||||
// change all values into their fixed representations
|
||||
let delegation_amount = U128::from_num(delegation_amount.u128());
|
||||
let circulating_supply = U128::from_num(self.reward_params.circulating_supply());
|
||||
let staking_supply = U128::from_num(self.reward_params.staking_supply());
|
||||
|
||||
let scaled_delegation_amount = delegation_amount / circulating_supply;
|
||||
let scaled_delegation_amount = delegation_amount / staking_supply;
|
||||
|
||||
// Div by zero checked above
|
||||
let delegator_reward =
|
||||
@@ -392,22 +392,21 @@ impl MixNodeBond {
|
||||
self.total_delegation.clone()
|
||||
}
|
||||
|
||||
pub fn stake_saturation(&self, circulating_supply: u128, rewarded_set_size: u32) -> U128 {
|
||||
self.total_bond_to_circulating_supply(circulating_supply)
|
||||
* U128::from_num(rewarded_set_size)
|
||||
pub fn stake_saturation(&self, staking_supply: u128, rewarded_set_size: u32) -> U128 {
|
||||
self.total_bond_to_staking_supply(staking_supply) * U128::from_num(rewarded_set_size)
|
||||
}
|
||||
|
||||
// TODO: There is an effect here when adding accumulted rewards to the total bond, ie accumulated rewards will not
|
||||
// affect lambda, but will affect sigma, in turn over time, if left unclaimed operator rewards will not compound, but
|
||||
// behave similarly to delegations.
|
||||
// The question is should this be taken into account when calculating operator rewards?
|
||||
pub fn pledge_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
|
||||
U128::from_num(self.pledge_amount().amount.u128()) / U128::from_num(circulating_supply)
|
||||
pub fn pledge_to_staking_supply(&self, staking_supply: u128) -> U128 {
|
||||
U128::from_num(self.pledge_amount().amount.u128()) / U128::from_num(staking_supply)
|
||||
}
|
||||
|
||||
pub fn total_bond_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
|
||||
pub fn total_bond_to_staking_supply(&self, staking_supply: u128) -> U128 {
|
||||
U128::from_num(self.pledge_amount().amount.u128() + self.total_delegation().amount.u128())
|
||||
/ U128::from_num(circulating_supply)
|
||||
/ U128::from_num(staking_supply)
|
||||
}
|
||||
|
||||
pub fn lambda_ticked(&self, params: &RewardParams) -> U128 {
|
||||
@@ -417,7 +416,7 @@ impl MixNodeBond {
|
||||
|
||||
pub fn lambda(&self, params: &RewardParams) -> U128 {
|
||||
// Ratio of a bond to the token circulating supply
|
||||
self.pledge_to_circulating_supply(params.circulating_supply())
|
||||
self.pledge_to_staking_supply(params.staking_supply())
|
||||
}
|
||||
|
||||
pub fn sigma_ticked(&self, params: &RewardParams) -> U128 {
|
||||
@@ -427,7 +426,7 @@ impl MixNodeBond {
|
||||
|
||||
pub fn sigma(&self, params: &RewardParams) -> U128 {
|
||||
// Ratio of a delegation to the the token circulating supply
|
||||
self.total_bond_to_circulating_supply(params.circulating_supply())
|
||||
self.total_bond_to_staking_supply(params.staking_supply())
|
||||
}
|
||||
|
||||
pub fn estimate_reward(
|
||||
@@ -515,9 +514,8 @@ impl MixNodeBond {
|
||||
}
|
||||
|
||||
pub fn sigma_ratio(&self, params: &RewardParams) -> U128 {
|
||||
if self.total_bond_to_circulating_supply(params.circulating_supply()) < params.one_over_k()
|
||||
{
|
||||
self.total_bond_to_circulating_supply(params.circulating_supply())
|
||||
if self.total_bond_to_staking_supply(params.staking_supply()) < params.one_over_k() {
|
||||
self.total_bond_to_staking_supply(params.staking_supply())
|
||||
} else {
|
||||
params.one_over_k()
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ impl NodeEpochRewards {
|
||||
) -> Result<Uint128, MixnetContractError> {
|
||||
// change all values into their fixed representations
|
||||
let delegation_amount = U128::from_num(delegation_amount.u128());
|
||||
let circulating_supply = U128::from_num(epoch_reward_params.circulating_supply());
|
||||
let staking_supply = U128::from_num(epoch_reward_params.staking_supply());
|
||||
|
||||
let scaled_delegation_amount = delegation_amount / circulating_supply;
|
||||
let scaled_delegation_amount = delegation_amount / staking_supply;
|
||||
|
||||
let check_div_by_zero =
|
||||
if let Some(value) = scaled_delegation_amount.checked_div(self.sigma()) {
|
||||
@@ -105,7 +105,8 @@ pub struct EpochRewardParams {
|
||||
epoch_reward_pool: Uint128,
|
||||
rewarded_set_size: Uint128,
|
||||
active_set_size: Uint128,
|
||||
circulating_supply: Uint128,
|
||||
#[serde(alias = "circulating_supply")]
|
||||
staking_supply: Uint128,
|
||||
sybil_resistance_percent: u8,
|
||||
active_set_work_factor: u8,
|
||||
}
|
||||
@@ -115,7 +116,7 @@ impl EpochRewardParams {
|
||||
epoch_reward_pool: u128,
|
||||
rewarded_set_size: u128,
|
||||
active_set_size: u128,
|
||||
circulating_supply: u128,
|
||||
staking_supply: u128,
|
||||
sybil_resistance_percent: u8,
|
||||
active_set_work_factor: u8,
|
||||
) -> EpochRewardParams {
|
||||
@@ -123,7 +124,7 @@ impl EpochRewardParams {
|
||||
epoch_reward_pool: Uint128::new(epoch_reward_pool),
|
||||
rewarded_set_size: Uint128::new(rewarded_set_size),
|
||||
active_set_size: Uint128::new(active_set_size),
|
||||
circulating_supply: Uint128::new(circulating_supply),
|
||||
staking_supply: Uint128::new(staking_supply),
|
||||
sybil_resistance_percent,
|
||||
active_set_work_factor,
|
||||
}
|
||||
@@ -136,7 +137,7 @@ impl EpochRewardParams {
|
||||
pub fn new_empty() -> Self {
|
||||
EpochRewardParams {
|
||||
epoch_reward_pool: Uint128::new(0),
|
||||
circulating_supply: Uint128::new(0),
|
||||
staking_supply: Uint128::new(0),
|
||||
sybil_resistance_percent: 0,
|
||||
rewarded_set_size: Uint128::new(0),
|
||||
active_set_size: Uint128::new(0),
|
||||
@@ -152,8 +153,8 @@ impl EpochRewardParams {
|
||||
self.active_set_size.u128()
|
||||
}
|
||||
|
||||
pub fn circulating_supply(&self) -> u128 {
|
||||
self.circulating_supply.u128()
|
||||
pub fn staking_supply(&self) -> u128 {
|
||||
self.staking_supply.u128()
|
||||
}
|
||||
|
||||
pub fn epoch_reward_pool(&self) -> u128 {
|
||||
@@ -252,8 +253,8 @@ impl RewardParams {
|
||||
self.epoch.rewarded_set_size.u128()
|
||||
}
|
||||
|
||||
pub fn circulating_supply(&self) -> u128 {
|
||||
self.epoch.circulating_supply.u128()
|
||||
pub fn staking_supply(&self) -> u128 {
|
||||
self.epoch.staking_supply.u128()
|
||||
}
|
||||
|
||||
pub fn reward_blockstamp(&self) -> u64 {
|
||||
|
||||
@@ -43,6 +43,7 @@ pub struct ContractStateParams {
|
||||
// subset of rewarded mixnodes that are actively receiving mix traffic
|
||||
// used to handle shorter-term (e.g. hourly) fluctuations of demand
|
||||
pub mixnode_active_set_size: u32,
|
||||
pub staking_supply: Uint128,
|
||||
}
|
||||
|
||||
impl Display for ContractStateParams {
|
||||
|
||||
@@ -26,5 +26,6 @@ nymsphinx-forwarding = { path = "../nymsphinx/forwarding" }
|
||||
nymsphinx-framing = { path = "../nymsphinx/framing" }
|
||||
nymsphinx-params = { path = "../nymsphinx/params" }
|
||||
nymsphinx-types = { path = "../nymsphinx/types" }
|
||||
task = { path = "../task" }
|
||||
validator-client = { path = "../client-libs/validator-client" }
|
||||
version-checker = { path = "../version-checker" }
|
||||
|
||||
@@ -24,6 +24,8 @@ pub enum RttError {
|
||||
ConnectionWriteTimeout(String),
|
||||
|
||||
UnexpectedReplySequence,
|
||||
|
||||
ShutdownReceived,
|
||||
}
|
||||
|
||||
impl Display for RttError {
|
||||
@@ -69,6 +71,9 @@ impl Display for RttError {
|
||||
f,
|
||||
"The received reply packet had an unexpected sequence number"
|
||||
),
|
||||
RttError::ShutdownReceived => {
|
||||
write!(f, "Shutdown signal received")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use std::fmt::{Display, Formatter};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, io, process};
|
||||
use task::ShutdownListener;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_util::codec::{Decoder, Encoder, Framed};
|
||||
@@ -18,13 +19,19 @@ use tokio_util::codec::{Decoder, Encoder, Framed};
|
||||
pub(crate) struct PacketListener {
|
||||
address: SocketAddr,
|
||||
connection_handler: Arc<ConnectionHandler>,
|
||||
shutdown: ShutdownListener,
|
||||
}
|
||||
|
||||
impl PacketListener {
|
||||
pub(crate) fn new(address: SocketAddr, identity: Arc<identity::KeyPair>) -> Self {
|
||||
pub(crate) fn new(
|
||||
address: SocketAddr,
|
||||
identity: Arc<identity::KeyPair>,
|
||||
shutdown: ShutdownListener,
|
||||
) -> Self {
|
||||
PacketListener {
|
||||
address,
|
||||
connection_handler: Arc::new(ConnectionHandler { identity }),
|
||||
shutdown,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,24 +41,37 @@ impl PacketListener {
|
||||
let listener = match TcpListener::bind(self.address).await {
|
||||
Ok(listener) => listener,
|
||||
Err(err) => {
|
||||
error!("Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address, err);
|
||||
error!(
|
||||
"Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?",
|
||||
self.address, err
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
info!("Started listening for echo packets on {}", self.address);
|
||||
|
||||
loop {
|
||||
let mut shutdown_listener = self.shutdown.clone();
|
||||
|
||||
while !shutdown_listener.is_shutdown() {
|
||||
// cloning the arc as each accepted socket is handled in separate task
|
||||
let connection_handler = Arc::clone(&self.connection_handler);
|
||||
let handler_shutdown_listener = self.shutdown.clone();
|
||||
|
||||
match listener.accept().await {
|
||||
Ok((socket, remote_addr)) => {
|
||||
debug!("New verloc connection from {}", remote_addr);
|
||||
tokio::select! {
|
||||
socket = listener.accept() => {
|
||||
match socket {
|
||||
Ok((socket, remote_addr)) => {
|
||||
debug!("New verloc connection from {}", remote_addr);
|
||||
|
||||
tokio::spawn(connection_handler.handle_connection(socket, remote_addr));
|
||||
tokio::spawn(connection_handler.handle_connection(socket, remote_addr, handler_shutdown_listener));
|
||||
}
|
||||
Err(err) => warn!("Failed to accept incoming connection - {:?}", err),
|
||||
}
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
log::trace!("PacketListener: Received shutdown");
|
||||
}
|
||||
Err(err) => warn!("Failed to accept incoming connection - {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,34 +87,46 @@ impl ConnectionHandler {
|
||||
packet.construct_reply(self.identity.private_key())
|
||||
}
|
||||
|
||||
pub(crate) async fn handle_connection(self: Arc<Self>, conn: TcpStream, remote: SocketAddr) {
|
||||
pub(crate) async fn handle_connection(
|
||||
self: Arc<Self>,
|
||||
conn: TcpStream,
|
||||
remote: SocketAddr,
|
||||
mut shutdown_listener: ShutdownListener,
|
||||
) {
|
||||
debug!("Starting connection handler for {:?}", remote);
|
||||
|
||||
let mut framed_conn = Framed::new(conn, EchoPacketCodec);
|
||||
while let Some(echo_packet) = framed_conn.next().await {
|
||||
// handle echo packet
|
||||
let reply_packet = match echo_packet {
|
||||
Ok(echo_packet) => self.handle_echo_packet(echo_packet),
|
||||
Err(err) => {
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {}. Closing the socket",
|
||||
err
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
while !shutdown_listener.is_shutdown() {
|
||||
tokio::select! {
|
||||
Some(echo_packet) = framed_conn.next() => {
|
||||
// handle echo packet
|
||||
let reply_packet = match echo_packet {
|
||||
Ok(echo_packet) => self.handle_echo_packet(echo_packet),
|
||||
Err(err) => {
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {}. Closing the socket",
|
||||
err
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// write back the reply (note the lack of framing)
|
||||
if let Err(err) = framed_conn
|
||||
.get_mut()
|
||||
.write_all(reply_packet.to_bytes().as_ref())
|
||||
.await
|
||||
{
|
||||
error!(
|
||||
"Failed to write reply packet back to the sender - {}. Closing the socket on our end",
|
||||
err
|
||||
);
|
||||
return;
|
||||
// write back the reply (note the lack of framing)
|
||||
if let Err(err) = framed_conn
|
||||
.get_mut()
|
||||
.write_all(reply_packet.to_bytes().as_ref())
|
||||
.await
|
||||
{
|
||||
error!(
|
||||
"Failed to write reply packet back to the sender - {}. Closing the socket on our end",
|
||||
err
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
trace!("ConnectionHandler: Shutdown received");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::verloc::listener::PacketListener;
|
||||
pub use crate::verloc::measurement::{AtomicVerlocResult, Verloc, VerlocResult};
|
||||
use crate::verloc::sender::{PacketSender, TestedNode};
|
||||
use crypto::asymmetric::identity;
|
||||
use futures::stream::FuturesUnordered;
|
||||
@@ -13,11 +12,14 @@ use rand::thread_rng;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use task::ShutdownListener;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::sleep;
|
||||
use url::Url;
|
||||
use version_checker::parse_version;
|
||||
|
||||
pub use crate::verloc::measurement::{AtomicVerlocResult, Verloc, VerlocResult};
|
||||
|
||||
pub mod error;
|
||||
pub(crate) mod listener;
|
||||
pub(crate) mod measurement;
|
||||
@@ -137,9 +139,10 @@ impl ConfigBuilder {
|
||||
|
||||
pub fn build(self) -> Config {
|
||||
// panics here are fine as those are only ever constructed at the initial setup
|
||||
if self.0.validator_api_urls.is_empty() {
|
||||
panic!("at least one validator endpoint must be provided")
|
||||
}
|
||||
assert!(
|
||||
!self.0.validator_api_urls.is_empty(),
|
||||
"at least one validator endpoint must be provided",
|
||||
);
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@@ -165,6 +168,7 @@ pub struct VerlocMeasurer {
|
||||
config: Config,
|
||||
packet_sender: Arc<PacketSender>,
|
||||
packet_listener: Arc<PacketListener>,
|
||||
shutdown_listener: ShutdownListener,
|
||||
|
||||
currently_used_api: usize,
|
||||
|
||||
@@ -177,7 +181,11 @@ pub struct VerlocMeasurer {
|
||||
}
|
||||
|
||||
impl VerlocMeasurer {
|
||||
pub fn new(mut config: Config, identity: Arc<identity::KeyPair>) -> Self {
|
||||
pub fn new(
|
||||
mut config: Config,
|
||||
identity: Arc<identity::KeyPair>,
|
||||
shutdown_listener: ShutdownListener,
|
||||
) -> Self {
|
||||
config.validator_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
VerlocMeasurer {
|
||||
@@ -187,11 +195,14 @@ impl VerlocMeasurer {
|
||||
config.packet_timeout,
|
||||
config.connection_timeout,
|
||||
config.delay_between_packets,
|
||||
shutdown_listener.clone(),
|
||||
)),
|
||||
packet_listener: Arc::new(PacketListener::new(
|
||||
config.listening_address,
|
||||
Arc::clone(&identity),
|
||||
shutdown_listener.clone(),
|
||||
)),
|
||||
shutdown_listener,
|
||||
currently_used_api: 0,
|
||||
validator_client: validator_client::ApiClient::new(
|
||||
config.validator_api_urls[0].clone(),
|
||||
@@ -222,7 +233,11 @@ impl VerlocMeasurer {
|
||||
tokio::spawn(packet_listener.run())
|
||||
}
|
||||
|
||||
async fn perform_measurement(&self, nodes_to_test: Vec<TestedNode>) {
|
||||
async fn perform_measurement(&self, nodes_to_test: Vec<TestedNode>) -> MeasurementOutcome {
|
||||
log::trace!("Performing measurements");
|
||||
|
||||
let mut shutdown_listener = self.shutdown_listener.clone();
|
||||
|
||||
for chunk in nodes_to_test.chunks(self.config.tested_nodes_batch_size) {
|
||||
let mut chunk_results = Vec::with_capacity(chunk.len());
|
||||
|
||||
@@ -246,33 +261,44 @@ impl VerlocMeasurer {
|
||||
.collect::<FuturesUnordered<_>>();
|
||||
|
||||
// exhaust the results
|
||||
while let Some(result) = measurement_chunk.next().await {
|
||||
// if we receive JoinError it means the task failed to get executed, so either there's a bigger issue with tokio
|
||||
// or there was a panic inside the task itself. In either case, we should just terminate ourselves.
|
||||
let execution_result = result.expect("the measurement task panicked!");
|
||||
let measurement_result = match execution_result.0 {
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"Failed to perform measurement for {} - {}",
|
||||
execution_result.1.to_base58_string(),
|
||||
err
|
||||
);
|
||||
None
|
||||
while !shutdown_listener.is_shutdown() {
|
||||
tokio::select! {
|
||||
Some(result) = measurement_chunk.next() => {
|
||||
// if we receive JoinError it means the task failed to get executed, so either there's a bigger issue with tokio
|
||||
// or there was a panic inside the task itself. In either case, we should just terminate ourselves.
|
||||
let execution_result = result.expect("the measurement task panicked!");
|
||||
let measurement_result = match execution_result.0 {
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"Failed to perform measurement for {} - {}",
|
||||
execution_result.1.to_base58_string(),
|
||||
err
|
||||
);
|
||||
None
|
||||
}
|
||||
Ok(result) => Some(result),
|
||||
};
|
||||
chunk_results.push(Verloc::new(execution_result.1, measurement_result));
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
trace!("Shutdown received while measuring");
|
||||
return MeasurementOutcome::Shutdown;
|
||||
}
|
||||
Ok(result) => Some(result),
|
||||
};
|
||||
chunk_results.push(Verloc::new(execution_result.1, measurement_result));
|
||||
}
|
||||
}
|
||||
|
||||
// update the results vector with chunks as they become available (by default every 50 nodes)
|
||||
self.results.append_results(chunk_results).await;
|
||||
}
|
||||
|
||||
MeasurementOutcome::Done
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
self.start_listening();
|
||||
loop {
|
||||
info!(target: "verloc", "Starting verloc measurements");
|
||||
|
||||
while !self.shutdown_listener.is_shutdown() {
|
||||
info!("Starting verloc measurements");
|
||||
// TODO: should we also measure gateways?
|
||||
|
||||
let all_mixes = match self.validator_client.get_cached_mixnodes().await {
|
||||
@@ -322,13 +348,32 @@ impl VerlocMeasurer {
|
||||
// on start of each run remove old results
|
||||
self.results.reset_results(tested_nodes.len()).await;
|
||||
|
||||
self.perform_measurement(tested_nodes).await;
|
||||
if let MeasurementOutcome::Shutdown = self.perform_measurement(tested_nodes).await {
|
||||
log::trace!("Shutting down after aborting measurements");
|
||||
break;
|
||||
}
|
||||
|
||||
// write current time to "run finished" field
|
||||
self.results.finish_measurements().await;
|
||||
|
||||
info!(target: "verloc", "Finished performing verloc measurements. The next one will happen in {:?}", self.config.testing_interval);
|
||||
sleep(self.config.testing_interval).await
|
||||
info!(
|
||||
"Finished performing verloc measurements. The next one will happen in {:?}",
|
||||
self.config.testing_interval
|
||||
);
|
||||
|
||||
tokio::select! {
|
||||
_ = sleep(self.config.testing_interval) => {},
|
||||
_ = self.shutdown_listener.recv() => {
|
||||
log::trace!("Shutdown received while sleeping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::trace!("Verloc: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
enum MeasurementOutcome {
|
||||
Done,
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ use crate::verloc::packet::{EchoPacket, ReplyPacket};
|
||||
use crypto::asymmetric::identity;
|
||||
use log::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{fmt, io};
|
||||
use task::ShutdownListener;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::time::sleep;
|
||||
@@ -27,6 +28,16 @@ impl TestedNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TestedNode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TestedNode(id: {}, address: {})",
|
||||
self.identity, self.address
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PacketSender {
|
||||
identity: Arc<identity::KeyPair>,
|
||||
// timeout for receiving before sending new one
|
||||
@@ -34,6 +45,7 @@ pub(crate) struct PacketSender {
|
||||
packet_timeout: Duration,
|
||||
connection_timeout: Duration,
|
||||
delay_between_packets: Duration,
|
||||
shutdown_listener: ShutdownListener,
|
||||
}
|
||||
|
||||
impl PacketSender {
|
||||
@@ -43,6 +55,7 @@ impl PacketSender {
|
||||
packet_timeout: Duration,
|
||||
connection_timeout: Duration,
|
||||
delay_between_packets: Duration,
|
||||
shutdown_listener: ShutdownListener,
|
||||
) -> Self {
|
||||
PacketSender {
|
||||
identity,
|
||||
@@ -50,6 +63,7 @@ impl PacketSender {
|
||||
packet_timeout,
|
||||
connection_timeout,
|
||||
delay_between_packets,
|
||||
shutdown_listener,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +83,8 @@ impl PacketSender {
|
||||
self: Arc<Self>,
|
||||
tested_node: TestedNode,
|
||||
) -> Result<Measurement, RttError> {
|
||||
let mut shutdown_listener = self.shutdown_listener.clone();
|
||||
|
||||
let mut conn = match tokio::time::timeout(
|
||||
self.connection_timeout,
|
||||
TcpStream::connect(tested_node.address),
|
||||
@@ -98,35 +114,40 @@ impl PacketSender {
|
||||
let start = tokio::time::Instant::now();
|
||||
// TODO: should we get the start time after or before actually sending the data?
|
||||
// there's going to definitely some scheduler and network stack bias here
|
||||
match tokio::time::timeout(
|
||||
self.packet_timeout,
|
||||
conn.write_all(packet.to_bytes().as_ref()),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Err(_timeout) => {
|
||||
let identity_string = tested_node.identity.to_base58_string();
|
||||
debug!(
|
||||
"failed to write echo packet to {} within {:?}. Stopping the test.",
|
||||
identity_string, self.packet_timeout
|
||||
);
|
||||
return Err(RttError::UnexpectedConnectionFailureWrite(
|
||||
identity_string,
|
||||
io::ErrorKind::TimedOut.into(),
|
||||
));
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
let identity_string = tested_node.identity.to_base58_string();
|
||||
debug!(
|
||||
"failed to write echo packet to {} - {}. Stopping the test.",
|
||||
identity_string, err
|
||||
);
|
||||
return Err(RttError::UnexpectedConnectionFailureWrite(
|
||||
identity_string,
|
||||
err,
|
||||
));
|
||||
}
|
||||
Ok(Ok(_)) => {}
|
||||
let packet_bytes = packet.to_bytes();
|
||||
|
||||
tokio::select! {
|
||||
write = tokio::time::timeout(self.packet_timeout, conn.write_all(packet_bytes.as_ref())) => {
|
||||
match write {
|
||||
Err(_timeout) => {
|
||||
let identity_string = tested_node.identity.to_base58_string();
|
||||
debug!(
|
||||
"failed to write echo packet to {} within {:?}. Stopping the test.",
|
||||
identity_string, self.packet_timeout
|
||||
);
|
||||
return Err(RttError::UnexpectedConnectionFailureWrite(
|
||||
identity_string,
|
||||
io::ErrorKind::TimedOut.into(),
|
||||
));
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
let identity_string = tested_node.identity.to_base58_string();
|
||||
debug!(
|
||||
"failed to write echo packet to {} - {}. Stopping the test.",
|
||||
identity_string, err
|
||||
);
|
||||
return Err(RttError::UnexpectedConnectionFailureWrite(
|
||||
identity_string,
|
||||
err,
|
||||
));
|
||||
}
|
||||
Ok(Ok(_)) => {}
|
||||
}
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
log::trace!("PacketSender: Received shutdown while sending");
|
||||
return Err(RttError::ShutdownReceived);
|
||||
},
|
||||
}
|
||||
|
||||
// there's absolutely no need to put a codec on ReplyPackets as we know exactly
|
||||
@@ -147,21 +168,28 @@ impl PacketSender {
|
||||
ReplyPacket::try_from_bytes(&buf, &tested_node.identity)
|
||||
};
|
||||
|
||||
let reply_packet =
|
||||
match tokio::time::timeout(self.packet_timeout, reply_packet_future).await {
|
||||
Ok(reply_packet) => reply_packet,
|
||||
Err(_timeout) => {
|
||||
// TODO: should we continue regardless (with the rest of the packets, or abandon the whole thing?)
|
||||
// Note: if we decide to continue, it would increase the complexity of the whole thing
|
||||
debug!(
|
||||
"failed to receive reply to our echo packet within {:?}. Stopping the test",
|
||||
self.packet_timeout
|
||||
);
|
||||
return Err(RttError::ConnectionReadTimeout(
|
||||
tested_node.identity.to_base58_string(),
|
||||
));
|
||||
let reply_packet = tokio::select! {
|
||||
reply = tokio::time::timeout(self.packet_timeout, reply_packet_future) => {
|
||||
match reply {
|
||||
Ok(reply_packet) => reply_packet,
|
||||
Err(_timeout) => {
|
||||
// TODO: should we continue regardless (with the rest of the packets, or abandon the whole thing?)
|
||||
// Note: if we decide to continue, it would increase the complexity of the whole thing
|
||||
debug!(
|
||||
"failed to receive reply to our echo packet within {:?}. Stopping the test",
|
||||
self.packet_timeout
|
||||
);
|
||||
return Err(RttError::ConnectionReadTimeout(
|
||||
tested_node.identity.to_base58_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
log::trace!("PacketSender: Received shutdown while waiting for reply");
|
||||
return Err(RttError::ShutdownReceived);
|
||||
}
|
||||
};
|
||||
|
||||
let reply_packet = reply_packet?;
|
||||
// make sure it's actually the expected packet...
|
||||
|
||||
@@ -57,6 +57,8 @@ pub const INITIAL_ACTIVE_SET_WORK_FACTOR: u8 = 10;
|
||||
pub const DEFAULT_FIRST_INTERVAL_START: OffsetDateTime =
|
||||
time::macros::datetime!(2022-01-01 12:00 UTC);
|
||||
|
||||
pub const INITIAL_STAKING_SUPPLY: Uint128 = Uint128::new(100_000_000_000_000);
|
||||
|
||||
pub fn debug_with_visibility<S: Into<String>>(api: &dyn Api, msg: S) {
|
||||
api.debug(&*format!("\n\n\n=========================================\n{}\n=========================================\n\n\n", msg.into()));
|
||||
}
|
||||
@@ -70,6 +72,7 @@ fn default_initial_state(owner: Addr, rewarding_validator_address: Addr) -> Cont
|
||||
minimum_gateway_pledge: INITIAL_GATEWAY_PLEDGE,
|
||||
mixnode_rewarded_set_size: INITIAL_MIXNODE_REWARDED_SET_SIZE,
|
||||
mixnode_active_set_size: INITIAL_MIXNODE_ACTIVE_SET_SIZE,
|
||||
staking_supply: INITIAL_STAKING_SUPPLY,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -432,7 +435,52 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
fn deal_with_zero_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
fn migrate_contract_state_params(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
use crate::mixnet_contract_settings::storage::CONTRACT_STATE;
|
||||
use cw_storage_plus::Item;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractState {
|
||||
pub owner: Addr,
|
||||
pub rewarding_validator_address: Addr,
|
||||
pub params: OldContractStateParams,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractStateParams {
|
||||
pub minimum_mixnode_pledge: Uint128,
|
||||
pub minimum_gateway_pledge: Uint128,
|
||||
pub mixnode_rewarded_set_size: u32,
|
||||
pub mixnode_active_set_size: u32,
|
||||
}
|
||||
|
||||
const OLD_CONTRACT_STATE: Item<'_, OldContractState> = Item::new("config");
|
||||
|
||||
let old_contract_state = OLD_CONTRACT_STATE.load(deps.storage)?;
|
||||
|
||||
let old_params = old_contract_state.params;
|
||||
|
||||
let new_params = ContractStateParams {
|
||||
minimum_mixnode_pledge: old_params.minimum_mixnode_pledge,
|
||||
minimum_gateway_pledge: old_params.minimum_gateway_pledge,
|
||||
mixnode_rewarded_set_size: old_params.mixnode_rewarded_set_size,
|
||||
mixnode_active_set_size: old_params.mixnode_active_set_size,
|
||||
staking_supply: INITIAL_STAKING_SUPPLY,
|
||||
};
|
||||
|
||||
let new_contract_state = ContractState {
|
||||
owner: old_contract_state.owner,
|
||||
rewarding_validator_address: old_contract_state.rewarding_validator_address,
|
||||
params: new_params,
|
||||
};
|
||||
|
||||
CONTRACT_STATE.save(deps.storage, &new_contract_state)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _deal_with_zero_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
// if there exists any delegation of 0 value, remove it
|
||||
let zero_delegations = delegations()
|
||||
.range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
|
||||
@@ -466,7 +514,7 @@ fn deal_with_zero_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
deal_with_zero_delegations(deps)?;
|
||||
migrate_contract_state_params(deps)?;
|
||||
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use super::storage;
|
||||
use cosmwasm_std::{Deps, StdResult};
|
||||
use mixnet_contract_common::{ContractStateParams, MixnetContractVersion};
|
||||
|
||||
pub(crate) fn query_contract_settings_params(deps: Deps<'_>) -> StdResult<ContractStateParams> {
|
||||
pub fn query_contract_settings_params(deps: Deps<'_>) -> StdResult<ContractStateParams> {
|
||||
storage::CONTRACT_STATE
|
||||
.load(deps.storage)
|
||||
.map(|settings| settings.params)
|
||||
@@ -51,6 +51,7 @@ pub(crate) mod tests {
|
||||
minimum_gateway_pledge: 456u128.into(),
|
||||
mixnode_rewarded_set_size: 1000,
|
||||
mixnode_active_set_size: 500,
|
||||
staking_supply: 1000000u128.into(),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ pub(crate) fn try_update_contract_settings(
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::contract::{INITIAL_GATEWAY_PLEDGE, INITIAL_MIXNODE_PLEDGE};
|
||||
use crate::contract::{INITIAL_GATEWAY_PLEDGE, INITIAL_MIXNODE_PLEDGE, INITIAL_STAKING_SUPPLY};
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnet_contract_settings::queries::query_rewarding_validator_address;
|
||||
use crate::mixnet_contract_settings::transactions::try_update_contract_settings;
|
||||
@@ -114,6 +114,7 @@ pub mod tests {
|
||||
minimum_gateway_pledge: INITIAL_GATEWAY_PLEDGE,
|
||||
mixnode_rewarded_set_size: 100,
|
||||
mixnode_active_set_size: 50,
|
||||
staking_supply: INITIAL_STAKING_SUPPLY,
|
||||
};
|
||||
|
||||
let initial_params = storage::CONTRACT_STATE
|
||||
|
||||
@@ -42,10 +42,21 @@ pub fn incr_reward_pool(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn decr_reward_pool(
|
||||
storage: &mut dyn Storage,
|
||||
amount: Uint128,
|
||||
) -> Result<Uint128, ContractError> {
|
||||
pub fn reward_accounting(storage: &mut dyn Storage, amount: Uint128) -> Result<(), ContractError> {
|
||||
decr_reward_pool(storage, amount)?;
|
||||
incr_staking_supply(storage, amount)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn incr_staking_supply(storage: &mut dyn Storage, amount: Uint128) -> Result<(), ContractError> {
|
||||
let mut contract_state =
|
||||
crate::mixnet_contract_settings::storage::CONTRACT_STATE.load(storage)?;
|
||||
contract_state.params.staking_supply += amount;
|
||||
crate::mixnet_contract_settings::storage::CONTRACT_STATE.save(storage, &contract_state)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decr_reward_pool(storage: &mut dyn Storage, amount: Uint128) -> Result<Uint128, ContractError> {
|
||||
REWARD_POOL.update(storage, |current_pool| {
|
||||
let stake = current_pool
|
||||
.checked_sub(amount)
|
||||
|
||||
@@ -678,7 +678,7 @@ pub(crate) fn try_reward_mixnode(
|
||||
)?;
|
||||
|
||||
// Take rewards out of the rewarding pool
|
||||
storage::decr_reward_pool(deps.storage, stored_node_result.reward())?;
|
||||
storage::reward_accounting(deps.storage, stored_node_result.reward())?;
|
||||
|
||||
let rewarding_result = RewardingResult {
|
||||
node_reward: stored_node_result.reward(),
|
||||
|
||||
+1
-2
@@ -4,8 +4,7 @@ x-network: &NETWORK
|
||||
BECH32_PREFIX: nymt
|
||||
DENOM: nymt
|
||||
STAKE_DENOM: nyxt
|
||||
WASMD_VERSION: v0.26.0
|
||||
WASMD_COMMIT_HASH: dc5ef6fe84f0a5e3b0894692a18cc48fb5b00adf
|
||||
WASMD_VERSION: v0.27.0
|
||||
|
||||
services:
|
||||
genesis_validator:
|
||||
|
||||
@@ -7,6 +7,6 @@ RUN ./setup.sh
|
||||
|
||||
FROM ubuntu:20.04
|
||||
COPY --from=go_builder /go/wasmd/build/nymd /root/nymd
|
||||
COPY --from=go_builder /go/wasmd/build/libwasmvm.so /root/libwasmvm.so
|
||||
COPY --from=go_builder /go/wasmd/build/libwasmvm*.so /root
|
||||
COPY init_and_start.sh .
|
||||
ENTRYPOINT ["./init_and_start.sh"]
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ue
|
||||
|
||||
git clone https://github.com/CosmWasm/wasmd.git
|
||||
cd wasmd
|
||||
git checkout "${WASMD_VERSION}"
|
||||
WASMD_COMMIT_HASH=$(git rev-parse HEAD)
|
||||
mkdir build
|
||||
go build \
|
||||
-o build/nymd -mod=readonly -tags "netgo,ledger" \
|
||||
@@ -14,5 +17,4 @@ go build \
|
||||
-X github.com/CosmWasm/wasmd/app.Bech32Prefix=${BECH32_PREFIX} \
|
||||
-X 'github.com/cosmos/cosmos-sdk/version.BuildTags=netgo,ledger'" \
|
||||
-trimpath ./cmd/wasmd
|
||||
WASMVM_SO=$(ldd build/nymd | grep libwasmvm.so | awk '{ print $3 }')
|
||||
cp "${WASMVM_SO}" build/
|
||||
find .. -type f -name 'libwasm*.so' -exec cp {} build \;
|
||||
|
||||
+7
-10
@@ -23,8 +23,7 @@
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-google-charts": "^3.0.15",
|
||||
"react-identicons": "^1.2.5",
|
||||
"react-router": "^5.2.1",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"react-router-dom": "6",
|
||||
"react-simple-maps": "^2.3.0",
|
||||
"react-tooltip": "^4.2.21",
|
||||
"use-clipboard-copy": "^0.2.0"
|
||||
@@ -33,11 +32,11 @@
|
||||
"@babel/core": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@storybook/addon-actions": "^6.4.19",
|
||||
"@storybook/addon-essentials": "^6.4.19",
|
||||
"@storybook/addon-interactions": "^6.4.19",
|
||||
"@storybook/addon-links": "^6.4.19",
|
||||
"@storybook/react": "^6.4.19",
|
||||
"@storybook/addon-actions": "^6.5.8",
|
||||
"@storybook/addon-essentials": "^6.5.8",
|
||||
"@storybook/addon-interactions": "^6.5.8",
|
||||
"@storybook/addon-links": "^6.5.8",
|
||||
"@storybook/react": "^6.5.8",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
@@ -50,8 +49,6 @@
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/react": "^17.0.34",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-router": "^5.1.18",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/react-simple-maps": "^1.0.6",
|
||||
"@types/react-tooltip": "^4.2.4",
|
||||
"@types/topojson-client": "^3.1.0",
|
||||
@@ -74,7 +71,7 @@
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-storybook": "^0.5.7",
|
||||
"eslint-plugin-storybook": "^0.5.12",
|
||||
"favicons-webpack-plugin": "^5.0.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
|
||||
import { CopyToClipboard } from '@nymproject/react';
|
||||
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard';
|
||||
import { Box } from '@mui/system';
|
||||
import { cellStyles } from './Universal-DataGrid';
|
||||
import { currencyToString } from '../utils/currency';
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { Menu } from '@mui/icons-material';
|
||||
import { NymLogo } from '@nymproject/react';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
import { useMainContext } from '../context/main';
|
||||
import { MobileDrawerClose } from '../icons/MobileDrawerClose';
|
||||
import { Footer } from './Footer';
|
||||
|
||||
@@ -14,7 +14,7 @@ import IconButton from '@mui/material/IconButton';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import { NymLogo } from '@nymproject/react';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
import { BIG_DIPPER, NYM_WEBSITE } from '../api/constants';
|
||||
import { useMainContext } from '../context/main';
|
||||
import { MobileDrawerClose } from '../icons/MobileDrawerClose';
|
||||
@@ -84,7 +84,7 @@ export const originalNavOptions: NavOptionType[] = [
|
||||
{
|
||||
id: 0,
|
||||
isActive: false,
|
||||
url: '/overview',
|
||||
url: '/',
|
||||
title: 'Overview',
|
||||
Icon: <OverviewSVG />,
|
||||
},
|
||||
@@ -343,7 +343,7 @@ export const Nav: React.FC = ({ children }) => {
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
<MuiLink component={Link} to="/overview" underline="none" color="inherit">
|
||||
<MuiLink component={Link} to="/" underline="none" color="inherit">
|
||||
Network Explorer
|
||||
</MuiLink>
|
||||
</Typography>
|
||||
|
||||
@@ -44,7 +44,7 @@ export const StatsCard: React.FC<StatsCardProps> = ({ icon, title, count, onClic
|
||||
</Box>
|
||||
{errorMsg && (
|
||||
<Typography variant="body2" sx={{ color: 'danger', padding: 2 }}>
|
||||
{errorMsg}
|
||||
{typeof errorMsg === 'string' ? errorMsg : errorMsg.message || 'Oh no! An error occurred'}
|
||||
</Typography>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
@@ -18,7 +18,7 @@ export const originalNavOptions: NavOptionType[] = [
|
||||
{
|
||||
id: 0,
|
||||
isActive: false,
|
||||
url: '/overview',
|
||||
url: '/',
|
||||
title: 'Overview',
|
||||
Icon: <OverviewSVG />,
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import { FallbackProps } from 'react-error-boundary';
|
||||
import { Alert, AlertTitle, Container } from '@mui/material';
|
||||
import { NymThemeProvider } from '@nymproject/mui-theme';
|
||||
import { NymLogo } from '@nymproject/react';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
|
||||
export const ErrorBoundaryContent: React.FC<FallbackProps> = ({ error }) => (
|
||||
<NymThemeProvider mode="dark">
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#121726;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<circle class="st0" cx="250" cy="250.1" r="239.8"/>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="4.980469e-02" y1="5613.9395" x2="500.0498" y2="5613.9395" gradientTransform="matrix(1 0 0 -1 0 5863.9897)">
|
||||
<stop offset="0" style="stop-color:#E1864B"/>
|
||||
<stop offset="1" style="stop-color:#DA465B"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M250,500.1c-17,0-33.9-1.7-50.4-5.1c-16.1-3.3-31.8-8.2-46.9-14.6c-14.8-6.3-29.1-14-42.5-23.1
|
||||
c-13.2-8.9-25.7-19.2-37-30.5c-11.3-11.3-21.6-23.8-30.5-37c-9-13.4-16.8-27.6-23.1-42.5c-6.4-15.1-11.3-30.9-14.6-46.9
|
||||
C1.8,284,0,267,0,250.1s1.7-33.9,5.1-50.4c3.3-16.1,8.2-31.8,14.6-46.9c6.3-14.8,14-29.1,23.1-42.5C51.7,97,62,84.6,73.3,73.3
|
||||
s23.8-21.6,37-30.5c13.4-9,27.7-16.8,42.5-23.1c15.1-6.4,30.9-11.3,46.9-14.6c16.5-3.4,33.4-5.1,50.4-5.1c17,0,33.9,1.7,50.4,5.1
|
||||
c16.1,3.3,31.8,8.2,46.9,14.6c14.8,6.3,29.1,14,42.5,23.1c13.2,8.9,25.7,19.2,37,30.5c11.3,11.3,21.6,23.8,30.5,37
|
||||
c9,13.4,16.8,27.7,23.1,42.5c6.4,15.1,11.3,30.9,14.6,46.9c3.4,16.5,5.1,33.4,5.1,50.4s-1.7,33.9-5.1,50.4
|
||||
c-3.3,16.1-8.2,31.8-14.6,46.9c-6.3,14.8-14,29.1-23.1,42.5c-8.9,13.2-19.2,25.7-30.5,37c-11.3,11.3-23.8,21.6-37,30.5
|
||||
c-13.4,9-27.7,16.8-42.5,23.1c-15.1,6.4-30.9,11.3-46.9,14.6C284,498.3,267,500.1,250,500.1z M250,20.5c-15.6,0-31.2,1.6-46.3,4.7
|
||||
c-14.7,3-29.2,7.5-43.1,13.4c-13.6,5.8-26.7,12.9-39,21.2c-12.2,8.2-23.6,17.7-34,28c-10.4,10.4-19.8,21.8-28,34
|
||||
c-8.3,12.3-15.4,25.4-21.2,39c-5.9,13.8-10.4,28.3-13.4,43.1c-3.1,15.1-4.7,30.7-4.7,46.3s1.6,31.2,4.7,46.3
|
||||
c3,14.7,7.5,29.2,13.4,43.1c5.8,13.6,12.9,26.7,21.2,39c8.2,12.2,17.7,23.6,28,34c10.4,10.4,21.8,19.8,34,28
|
||||
c12.3,8.3,25.4,15.4,39,21.2c13.8,5.9,28.3,10.4,43.1,13.4c15.1,3.1,30.7,4.7,46.3,4.7c15.6,0,31.2-1.6,46.3-4.7
|
||||
c14.7-3,29.2-7.5,43.1-13.4c13.6-5.8,26.7-12.9,39-21.2c12.2-8.2,23.6-17.7,34-28c10.4-10.4,19.8-21.8,28-34
|
||||
c8.3-12.3,15.4-25.4,21.2-39c5.9-13.8,10.4-28.3,13.4-43.1c3.1-15.1,4.7-30.7,4.7-46.3s-1.6-31.2-4.7-46.3
|
||||
c-3-14.7-7.5-29.2-13.4-43.1c-5.8-13.6-12.9-26.7-21.2-39c-8.2-12.2-17.7-23.6-28-34c-10.4-10.4-21.8-19.8-34-28
|
||||
c-12.3-8.3-25.4-15.4-39-21.2c-13.8-5.9-28.3-10.4-43.1-13.4C281.2,22,265.6,20.5,250,20.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st2" d="M369.8,341.2h-52.8l-144-142v142h-42.8V158.9h54.1l144,141.9V158.9h41.5V341.2z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,12 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Button, Grid, Paper, Typography } from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { NymLogo } from '@nymproject/react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
import { useMainContext } from '../../context/main';
|
||||
|
||||
export const Page404: React.FC = () => {
|
||||
const history = useHistory();
|
||||
const navigate = useNavigate();
|
||||
const { mode } = useMainContext();
|
||||
const theme = useTheme();
|
||||
return (
|
||||
@@ -37,7 +37,7 @@ export const Page404: React.FC = () => {
|
||||
bgcolor: theme.palette.primary.main,
|
||||
color: theme.palette.secondary.main,
|
||||
}}
|
||||
onClick={() => history.push('/overview')}
|
||||
onClick={() => navigate('/')}
|
||||
>
|
||||
Overview
|
||||
</Button>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid';
|
||||
import { Button, Card, Grid, Link as MuiLink } from '@mui/material';
|
||||
import { Link as RRDLink, useParams } from 'react-router-dom';
|
||||
import { Link as RRDLink, useParams, useNavigate } from 'react-router-dom';
|
||||
import { SelectChangeEvent } from '@mui/material/Select';
|
||||
import { SxProps } from '@mui/system';
|
||||
import { Theme, useTheme } from '@mui/material/styles';
|
||||
import { useHistory } from 'react-router';
|
||||
import { CopyToClipboard } from '@nymproject/react';
|
||||
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard';
|
||||
import { useMainContext } from '../../context/main';
|
||||
import { MixnodeRowType, mixnodeToGridRow } from '../../components/MixNodes';
|
||||
import { TableToolbar } from '../../components/TableToolbar';
|
||||
@@ -42,7 +41,7 @@ export const PageMixnodes: React.FC = () => {
|
||||
const [searchTerm, setSearchTerm] = React.useState<string>('');
|
||||
const theme = useTheme();
|
||||
const { status } = useParams<{ status: MixnodeStatusWithAll | undefined }>();
|
||||
const history = useHistory();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSearch = (str: string) => {
|
||||
setSearchTerm(str.toLowerCase());
|
||||
@@ -74,7 +73,7 @@ export const PageMixnodes: React.FC = () => {
|
||||
}, [status]);
|
||||
|
||||
const handleMixnodeStatusChanged = (newStatus?: MixnodeStatusWithAll) => {
|
||||
history.push(
|
||||
navigate(
|
||||
newStatus && newStatus !== MixnodeStatusWithAll.all
|
||||
? `/network-components/mixnodes/${newStatus}`
|
||||
: '/network-components/mixnodes',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Grid, Link, Typography } from '@mui/material';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { WorldMap } from '../../components/WorldMap';
|
||||
import { useMainContext } from '../../context/main';
|
||||
import { formatNumber } from '../../utils';
|
||||
@@ -17,7 +17,7 @@ import { Icons } from '../../components/Icons';
|
||||
|
||||
export const PageOverview: React.FC = () => {
|
||||
const theme = useTheme();
|
||||
const history = useHistory();
|
||||
const navigate = useNavigate();
|
||||
const { summaryOverview, gateways, validators, block, countryData } = useMainContext();
|
||||
return (
|
||||
<Box component="main" sx={{ flexGrow: 1 }}>
|
||||
@@ -31,7 +31,7 @@ export const PageOverview: React.FC = () => {
|
||||
<>
|
||||
<Grid item xs={12} md={4}>
|
||||
<StatsCard
|
||||
onClick={() => history.push('/network-components/mixnodes')}
|
||||
onClick={() => navigate('/network-components/mixnodes')}
|
||||
title="Mixnodes"
|
||||
icon={<MixnodesSVG />}
|
||||
count={summaryOverview.data?.mixnodes.count || ''}
|
||||
@@ -40,7 +40,7 @@ export const PageOverview: React.FC = () => {
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<StatsCard
|
||||
onClick={() => history.push('/network-components/mixnodes/active')}
|
||||
onClick={() => navigate('/network-components/mixnodes/active')}
|
||||
title="Active nodes"
|
||||
icon={<Icons.Mixnodes.Status.Active />}
|
||||
color={theme.palette.nym.networkExplorer.mixnodes.status.active}
|
||||
@@ -50,7 +50,7 @@ export const PageOverview: React.FC = () => {
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<StatsCard
|
||||
onClick={() => history.push('/network-components/mixnodes/standby')}
|
||||
onClick={() => navigate('/network-components/mixnodes/standby')}
|
||||
title="Standby nodes"
|
||||
color={theme.palette.nym.networkExplorer.mixnodes.status.standby}
|
||||
icon={<Icons.Mixnodes.Status.Standby />}
|
||||
@@ -63,7 +63,7 @@ export const PageOverview: React.FC = () => {
|
||||
{gateways && (
|
||||
<Grid item xs={12} md={6}>
|
||||
<StatsCard
|
||||
onClick={() => history.push('/network-components/gateways')}
|
||||
onClick={() => navigate('/network-components/gateways')}
|
||||
title="Gateways"
|
||||
count={gateways?.data?.length || ''}
|
||||
errorMsg={gateways?.error}
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
||||
import { Routes as ReactRouterRoutes, Route } from 'react-router-dom';
|
||||
import { PageOverview } from '../pages/Overview';
|
||||
import { PageMixnodesMap } from '../pages/MixnodesMap';
|
||||
import { Page404 } from '../pages/404';
|
||||
import { NetworkComponentsRoutes } from './network-components';
|
||||
|
||||
export const Routes: React.FC = () => (
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect to="/overview" />
|
||||
</Route>
|
||||
<Route exact path="/overview">
|
||||
<PageOverview />
|
||||
</Route>
|
||||
<Route path="/network-components">
|
||||
<NetworkComponentsRoutes />
|
||||
</Route>
|
||||
<Route path="/nodemap">
|
||||
<PageMixnodesMap />
|
||||
</Route>
|
||||
<Route component={Page404} />
|
||||
</Switch>
|
||||
<ReactRouterRoutes>
|
||||
<Route path="/" element={<PageOverview />} />
|
||||
<Route path="/network-components/*" element={<NetworkComponentsRoutes />} />
|
||||
<Route path="/nodemap" element={<PageMixnodesMap />} />
|
||||
<Route path="*" element={Page404} />
|
||||
</ReactRouterRoutes>
|
||||
);
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
import * as React from 'react';
|
||||
import { Switch, Route, RouteComponentProps } from 'react-router-dom';
|
||||
import { Routes as ReactRouterRoutes, Route, useNavigate } from 'react-router-dom';
|
||||
import { BIG_DIPPER } from '../api/constants';
|
||||
import { PageGateways } from '../pages/Gateways';
|
||||
import { PageMixnodeDetail } from '../pages/MixnodeDetail';
|
||||
import { PageMixnodes } from '../pages/Mixnodes';
|
||||
|
||||
const ValidatorRoute: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
window.open(`${BIG_DIPPER}/validators`);
|
||||
navigate(-1);
|
||||
return null;
|
||||
};
|
||||
|
||||
export const NetworkComponentsRoutes: React.FC = () => (
|
||||
<Switch>
|
||||
<Route exact path="/network-components/mixnodes/:status">
|
||||
<PageMixnodes />
|
||||
</Route>
|
||||
<Route exact path="/network-components/mixnodes">
|
||||
<PageMixnodes />
|
||||
</Route>
|
||||
<Route path="/network-components/mixnode/:id">
|
||||
<PageMixnodeDetail />
|
||||
</Route>
|
||||
<Route path="/network-components/gateways">
|
||||
<PageGateways />
|
||||
</Route>
|
||||
<Route
|
||||
path="/network-components/validators"
|
||||
component={(props: RouteComponentProps) => {
|
||||
window.open(`${BIG_DIPPER}/validators`);
|
||||
props.history.goBack();
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
<Route path="/network-components/gateways/:id">
|
||||
<h1> Specific Gateways ID</h1>
|
||||
</Route>
|
||||
</Switch>
|
||||
<ReactRouterRoutes>
|
||||
<Route path="mixnodes/:status" element={<PageMixnodes />} />
|
||||
<Route path="mixnodes" element={<PageMixnodes />} />
|
||||
<Route path="mixnode/:id" element={<PageMixnodeDetail />} />
|
||||
<Route path="gateways" element={<PageGateways />} />
|
||||
<Route path="validators" element={<ValidatorRoute />} />
|
||||
<Route path="gateways/:id" element={<h1> Specific Gateways ID</h1>} />
|
||||
</ReactRouterRoutes>
|
||||
);
|
||||
|
||||
@@ -213,7 +213,7 @@ impl MixNode {
|
||||
packet_sender
|
||||
}
|
||||
|
||||
fn start_verloc_measurements(&self) -> AtomicVerlocResult {
|
||||
fn start_verloc_measurements(&self, shutdown: ShutdownListener) -> AtomicVerlocResult {
|
||||
info!("Starting the round-trip-time measurer...");
|
||||
|
||||
// this is a sanity check to make sure we didn't mess up with the minimum version at some point
|
||||
@@ -246,7 +246,8 @@ impl MixNode {
|
||||
.validator_api_urls(self.config.get_validator_api_endpoints())
|
||||
.build();
|
||||
|
||||
let mut verloc_measurer = VerlocMeasurer::new(config, Arc::clone(&self.identity_keypair));
|
||||
let mut verloc_measurer =
|
||||
VerlocMeasurer::new(config, Arc::clone(&self.identity_keypair), shutdown);
|
||||
let atomic_verloc_results = verloc_measurer.get_verloc_results_pointer();
|
||||
tokio::spawn(async move { verloc_measurer.run().await });
|
||||
atomic_verloc_results
|
||||
@@ -331,9 +332,11 @@ impl MixNode {
|
||||
delay_forwarding_channel,
|
||||
shutdown.subscribe(),
|
||||
);
|
||||
let atomic_verloc_results = self.start_verloc_measurements(shutdown.subscribe());
|
||||
|
||||
// TODO: these two also needs to be shutdown
|
||||
let atomic_verloc_results = self.start_verloc_measurements();
|
||||
// Rocket handles shutdown on it's own, but its shutdown handling should be incorporated
|
||||
// with that of the rest of the tasks.
|
||||
// Currently it's runtime is forcefully terminated once the mixnode exits.
|
||||
self.start_http_api(atomic_verloc_results, node_stats_pointer);
|
||||
|
||||
info!("Finished nym mixnode startup procedure - it should now be able to receive mix traffic!");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* This is a mock for Tauri's API package (@tauri-apps/api/app), to prevent stories from being excluded, because they either use
|
||||
* or import dependencies that use Tauri.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
getVersion: () => undefined
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export interface AppEnv { ADMIN_ADDRESS: string | null, SHOW_TERMINAL: string | null, }
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export interface ValidatorUrl { url: string, name: string | null, }
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export interface Validator { nymd_url: string, nymd_name: string | null, api_url: string | null, }
|
||||
@@ -17,6 +17,7 @@ pub struct TauriContractStateParams {
|
||||
minimum_gateway_pledge: String,
|
||||
mixnode_rewarded_set_size: u32,
|
||||
mixnode_active_set_size: u32,
|
||||
staking_supply: String,
|
||||
}
|
||||
|
||||
impl From<ContractStateParams> for TauriContractStateParams {
|
||||
@@ -26,6 +27,7 @@ impl From<ContractStateParams> for TauriContractStateParams {
|
||||
minimum_gateway_pledge: p.minimum_gateway_pledge.to_string(),
|
||||
mixnode_rewarded_set_size: p.mixnode_rewarded_set_size,
|
||||
mixnode_active_set_size: p.mixnode_active_set_size,
|
||||
staking_supply: p.staking_supply.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +41,7 @@ impl TryFrom<TauriContractStateParams> for ContractStateParams {
|
||||
minimum_gateway_pledge: Uint128::try_from(p.minimum_gateway_pledge.as_str())?,
|
||||
mixnode_rewarded_set_size: p.mixnode_rewarded_set_size,
|
||||
mixnode_active_set_size: p.mixnode_active_set_size,
|
||||
staking_supply: Uint128::try_from(p.staking_supply.as_str())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@nymproject/mui-theme": "^1.0.0",
|
||||
"@nymproject/react": "^1.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@storybook/react": "^6.4.22",
|
||||
"@storybook/react": "^6.5.8",
|
||||
"@tauri-apps/api": "^1.0.0-rc.1",
|
||||
"bs58": "^4.0.1",
|
||||
"clsx": "^1.1.1",
|
||||
@@ -68,8 +68,6 @@
|
||||
"@types/qrcode.react": "^1.0.2",
|
||||
"@types/react": "^17.0.34",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-router": "^5.1.18",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/semver": "^7.3.8",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
@@ -91,7 +89,7 @@
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-storybook": "^0.5.7",
|
||||
"eslint-plugin-storybook": "^0.5.12",
|
||||
"favicons": "^6.2.2",
|
||||
"favicons-webpack-plugin": "^5.0.2",
|
||||
"file-loader": "^6.2.0",
|
||||
|
||||
@@ -63,6 +63,32 @@ const AdminForm: React.FC<{
|
||||
helperText={errors?.mixnode_active_set_size?.message}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
{...register('mixnode_rewarded_set_size', { valueAsNumber: true })}
|
||||
required
|
||||
variant="outlined"
|
||||
id="mixnode_rewarded_set_size"
|
||||
name="mixnode_rewarded_set_size"
|
||||
label="Mixnode Rewarded Set Size"
|
||||
fullWidth
|
||||
error={!!errors.mixnode_rewarded_set_size}
|
||||
helperText={errors?.mixnode_rewarded_set_size?.message}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
{...register('staking_supply', { valueAsNumber: true })}
|
||||
required
|
||||
variant="outlined"
|
||||
id="staking_supply"
|
||||
name="staking_supply"
|
||||
label="Staking Supply"
|
||||
fullWidth
|
||||
error={!!errors.mixnode_rewarded_set_size}
|
||||
helperText={errors?.mixnode_rewarded_set_size?.message}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
<Grid
|
||||
|
||||
@@ -62,6 +62,8 @@ export const SendWizard = () => {
|
||||
};
|
||||
|
||||
const handleSend = async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
const formState = methods.getValues();
|
||||
|
||||
const hasEnoughFunds = await checkHasEnoughFunds(formState.amount.amount);
|
||||
@@ -72,7 +74,6 @@ export const SendWizard = () => {
|
||||
handlePreviousStep();
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
setActiveStep((s) => s + 1);
|
||||
|
||||
send({
|
||||
@@ -89,13 +90,14 @@ export const SendWizard = () => {
|
||||
...details,
|
||||
tx_hash,
|
||||
});
|
||||
setIsLoading(false);
|
||||
userBalance.fetchBalance();
|
||||
})
|
||||
.catch((e) => {
|
||||
setRequestError(e);
|
||||
setIsLoading(false);
|
||||
Console.error(e);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
|
||||
export interface AppEnv { ADMIN_ADDRESS: string | null, SHOW_TERMINAL: string | null, }
|
||||
export interface AppEnv {
|
||||
ADMIN_ADDRESS: string | null;
|
||||
SHOW_TERMINAL: string | null;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
|
||||
export interface Epoch { id: number, start: bigint, end: bigint, duration_seconds: bigint, }
|
||||
export interface Epoch {
|
||||
id: number;
|
||||
start: bigint;
|
||||
end: bigint;
|
||||
duration_seconds: bigint;
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
export type Network = "QA" | "SANDBOX" | "MAINNET";
|
||||
export type Network = 'QA' | 'SANDBOX' | 'MAINNET';
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
|
||||
export interface TauriContractStateParams { minimum_mixnode_pledge: string, minimum_gateway_pledge: string, mixnode_rewarded_set_size: number, mixnode_active_set_size: number, }
|
||||
export interface TauriContractStateParams {
|
||||
minimum_mixnode_pledge: string;
|
||||
minimum_gateway_pledge: string;
|
||||
mixnode_rewarded_set_size: number;
|
||||
mixnode_active_set_size: number;
|
||||
staking_supply: string;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
|
||||
export interface ValidatorUrl { url: string, name: string | null, }
|
||||
export interface ValidatorUrl {
|
||||
url: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { ValidatorUrl } from "./ValidatorUrl";
|
||||
import type { ValidatorUrl } from './ValidatorUrl';
|
||||
|
||||
export interface ValidatorUrls { urls: Array<ValidatorUrl>, }
|
||||
export interface ValidatorUrls {
|
||||
urls: Array<ValidatorUrl>;
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@storybook/addon-actions": "^6.4.19",
|
||||
"@storybook/addon-essentials": "^6.4.19",
|
||||
"@storybook/addon-interactions": "^6.4.19",
|
||||
"@storybook/addon-links": "^6.4.19",
|
||||
"@storybook/builder-webpack5": "^6.4.19",
|
||||
"@storybook/manager-webpack5": "^6.4.19",
|
||||
"@storybook/react": "^6.4.19",
|
||||
"@storybook/addon-actions": "^6.5.8",
|
||||
"@storybook/addon-essentials": "^6.5.8",
|
||||
"@storybook/addon-interactions": "^6.5.8",
|
||||
"@storybook/addon-links": "^6.5.8",
|
||||
"@storybook/builder-webpack5": "^6.5.8",
|
||||
"@storybook/manager-webpack5": "^6.5.8",
|
||||
"@storybook/react": "^6.5.8",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@types/flat": "^5.0.2",
|
||||
@@ -63,7 +63,7 @@
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-storybook": "^0.5.7",
|
||||
"eslint-plugin-storybook": "^0.5.12",
|
||||
"jest": "^27.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
||||
@@ -108,7 +108,7 @@ impl<C> ValidatorCacheRefresher<C> {
|
||||
.map(|mixnode_bond| {
|
||||
let stake_saturation = mixnode_bond
|
||||
.stake_saturation(
|
||||
interval_reward_params.circulating_supply(),
|
||||
interval_reward_params.staking_supply(),
|
||||
interval_reward_params.rewarded_set_size() as u32,
|
||||
)
|
||||
.to_num();
|
||||
|
||||
@@ -188,7 +188,7 @@ pub(crate) async fn get_mixnode_stake_saturation(
|
||||
let interval_reward_params = interval_reward_params.into_inner();
|
||||
|
||||
let saturation = bond.mixnode_bond.stake_saturation(
|
||||
interval_reward_params.circulating_supply(),
|
||||
interval_reward_params.staking_supply(),
|
||||
interval_reward_params.rewarded_set_size() as u32,
|
||||
);
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ impl<C> Client<C> {
|
||||
* interval_reward_percent as u128,
|
||||
state.mixnode_rewarded_set_size as u128,
|
||||
state.mixnode_active_set_size as u128,
|
||||
this.get_circulating_supply().await?,
|
||||
state.staking_supply.u128(),
|
||||
this.get_sybil_resistance_percent().await?,
|
||||
this.get_active_set_work_factor().await?,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user