Merge remote-tracking branch 'origin/develop' into feature/hrycyszynvpn

This commit is contained in:
Jon Häggblad
2022-06-10 16:13:21 +02:00
51 changed files with 1429 additions and 1602 deletions
+7
View File
@@ -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
View File
@@ -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 {
+1
View File
@@ -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")
}
}
}
}
+64 -32
View File
@@ -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");
}
}
}
}
+71 -26
View File
@@ -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,
}
+72 -44
View File
@@ -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...
+50 -2
View File
@@ -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
+15 -4
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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:
+1 -1
View File
@@ -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"]
+4 -2
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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';
+1 -1
View File
@@ -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';
+3 -3
View File
@@ -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>
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -18,7 +18,7 @@ export const originalNavOptions: NavOptionType[] = [
{
id: 0,
isActive: false,
url: '/overview',
url: '/',
title: 'Overview',
Icon: <OverviewSVG />,
},
+1 -1
View File
@@ -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">
-37
View File
@@ -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

+4 -4
View File
@@ -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>
+4 -5
View File
@@ -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',
+6 -6
View File
@@ -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}
+7 -16
View File
@@ -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>
);
+16 -26
View File
@@ -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>
);
+7 -4
View File
@@ -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!");
+8
View File
@@ -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, }
+3
View File
@@ -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())?,
})
}
}
+2 -4
View File
@@ -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",
+26
View File
@@ -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
+5 -3
View File
@@ -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);
});
};
+4 -2
View File
@@ -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;
}
+6 -2
View File
@@ -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
View File
@@ -1,2 +1 @@
export type Network = "QA" | "SANDBOX" | "MAINNET";
export type Network = 'QA' | 'SANDBOX' | 'MAINNET';
+7 -2
View File
@@ -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;
}
+4 -2
View File
@@ -1,2 +1,4 @@
export interface ValidatorUrl { url: string, name: string | null, }
export interface ValidatorUrl {
url: string;
name: string | null;
}
+4 -2
View File
@@ -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>;
}
+8 -8
View File
@@ -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",
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -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,
);
+1 -1
View File
@@ -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?,
);
+962 -1316
View File
File diff suppressed because it is too large Load Diff