Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0c29f1d17 | |||
| 7abfe27e57 | |||
| 7ca801fff3 | |||
| 8a92cca448 | |||
| 4308f602ea | |||
| 3ee1e541ff | |||
| 866309cedf | |||
| 2d57ed49e8 | |||
| a08cc64fc7 | |||
| 23892fec8c | |||
| d807f66944 | |||
| 0861304368 | |||
| 077ea25990 | |||
| 77679064de | |||
| 2052577174 | |||
| 24a859d03c | |||
| b898ad3e97 | |||
| af3a216f71 | |||
| 7866cb0ae8 | |||
| 40adedb5e1 | |||
| c1660c2b27 | |||
| 84b497ab20 | |||
| 14d5e112d0 | |||
| 620c5e1188 | |||
| 60c740f723 |
@@ -376,7 +376,11 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn simulate<I, M>(&self, messages: I) -> Result<SimulateResponse, NyxdError>
|
||||
pub async fn simulate<I, M>(
|
||||
&self,
|
||||
messages: I,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<SimulateResponse, NyxdError>
|
||||
where
|
||||
I: IntoIterator<Item = M> + Send,
|
||||
M: Msg,
|
||||
@@ -391,7 +395,7 @@ where
|
||||
.map_err(|_| {
|
||||
NyxdError::SerializationError("custom simulate messages".to_owned())
|
||||
})?,
|
||||
"simulating execution of transactions",
|
||||
memo,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ impl GatewayBond {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayNodeDetailsResponse {
|
||||
pub identity_key: String,
|
||||
pub sphinx_key: String,
|
||||
@@ -88,6 +88,7 @@ pub struct GatewayNodeDetailsResponse {
|
||||
pub data_store: String,
|
||||
|
||||
pub network_requester: Option<GatewayNetworkRequesterDetails>,
|
||||
pub ip_packet_router: Option<GatewayIpPacketRouterDetails>,
|
||||
}
|
||||
|
||||
impl fmt::Display for GatewayNodeDetailsResponse {
|
||||
@@ -98,7 +99,7 @@ impl fmt::Display for GatewayNodeDetailsResponse {
|
||||
writeln!(f, "bind address: {}", self.bind_address)?;
|
||||
writeln!(
|
||||
f,
|
||||
"mix Port: {}, clients port: {}",
|
||||
"mix port: {}, clients port: {}",
|
||||
self.mix_port, self.clients_port
|
||||
)?;
|
||||
|
||||
@@ -107,11 +108,15 @@ impl fmt::Display for GatewayNodeDetailsResponse {
|
||||
if let Some(nr) = &self.network_requester {
|
||||
nr.fmt(f)?;
|
||||
}
|
||||
|
||||
if let Some(ipr) = &self.ip_packet_router {
|
||||
ipr.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayNetworkRequesterDetails {
|
||||
pub enabled: bool,
|
||||
|
||||
@@ -149,7 +154,7 @@ impl fmt::Display for GatewayNetworkRequesterDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayIpPacketRouterDetails {
|
||||
pub enabled: bool,
|
||||
|
||||
@@ -164,7 +169,7 @@ pub struct GatewayIpPacketRouterDetails {
|
||||
|
||||
impl fmt::Display for GatewayIpPacketRouterDetails {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "IP packet router:")?;
|
||||
writeln!(f, "ip packet router:")?;
|
||||
writeln!(f, "\tenabled: {}", self.enabled)?;
|
||||
writeln!(f, "\tconfig path: {}", self.config_path)?;
|
||||
|
||||
|
||||
@@ -127,7 +127,26 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse,
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
let mut current_epoch = CURRENT_EPOCH.load(deps.storage)?;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.public_key_submission_time_secs = 1200;
|
||||
current_epoch.time_configuration.dealing_exchange_time_secs = 1200;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.verification_key_submission_time_secs = 600;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.verification_key_validation_time_secs = 600;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.verification_key_finalization_time_secs = 600;
|
||||
current_epoch.time_configuration.in_progress_time_secs = 60 * 60 * 24 * 365 * 10;
|
||||
|
||||
CURRENT_EPOCH.save(deps.storage, ¤t_epoch)?;
|
||||
|
||||
//
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ type DealingKey<'a> = &'a Addr;
|
||||
// if TOTAL_DEALINGS is modified to anything other then current value (5), this part will also need
|
||||
// to be modified
|
||||
pub(crate) const DEALINGS_BYTES: [Map<'_, DealingKey<'_>, ContractSafeBytes>; TOTAL_DEALINGS] = [
|
||||
Map::new("dbyt1"),
|
||||
Map::new("dbyt2"),
|
||||
Map::new("dbyt3"),
|
||||
Map::new("dbyt4"),
|
||||
Map::new("dbyt5"),
|
||||
Map::new("dbyt1-tmp2"),
|
||||
Map::new("dbyt2-tmp2"),
|
||||
Map::new("dbyt3-tmp2"),
|
||||
Map::new("dbyt4-tmp2"),
|
||||
Map::new("dbyt5-tmp2"),
|
||||
];
|
||||
|
||||
@@ -103,10 +103,50 @@ fn load_network_requester_details(
|
||||
)
|
||||
}
|
||||
|
||||
fn load_ip_packet_router_details(
|
||||
config: &Config,
|
||||
ip_packet_router_config: &nym_ip_packet_router::Config,
|
||||
) -> Result<api_requests::v1::ip_packet_router::models::IpPacketRouter, GatewayError> {
|
||||
let identity_public_key: identity::PublicKey = load_public_key(
|
||||
&ip_packet_router_config
|
||||
.storage_paths
|
||||
.common_paths
|
||||
.keys
|
||||
.public_identity_key_file,
|
||||
"ip packet router identity",
|
||||
)?;
|
||||
|
||||
let dh_public_key: encryption::PublicKey = load_public_key(
|
||||
&ip_packet_router_config
|
||||
.storage_paths
|
||||
.common_paths
|
||||
.keys
|
||||
.public_encryption_key_file,
|
||||
"ip packet router diffie hellman",
|
||||
)?;
|
||||
|
||||
let gateway_identity_public_key: identity::PublicKey = load_public_key(
|
||||
&config.storage_paths.keys.public_identity_key_file,
|
||||
"gateway identity",
|
||||
)?;
|
||||
|
||||
Ok(api_requests::v1::ip_packet_router::models::IpPacketRouter {
|
||||
encoded_identity_key: identity_public_key.to_base58_string(),
|
||||
encoded_x25519_key: dh_public_key.to_base58_string(),
|
||||
address: Recipient::new(
|
||||
identity_public_key,
|
||||
dh_public_key,
|
||||
gateway_identity_public_key,
|
||||
)
|
||||
.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) struct HttpApiBuilder<'a> {
|
||||
gateway_config: &'a Config,
|
||||
network_requester_config: Option<&'a nym_network_requester::Config>,
|
||||
exit_policy: Option<UsedExitPolicy>,
|
||||
ip_packet_router_config: Option<&'a nym_ip_packet_router::Config>,
|
||||
|
||||
identity_keypair: &'a identity::KeyPair,
|
||||
// TODO: this should be a wg specific key and not re-used sphinx
|
||||
@@ -124,6 +164,7 @@ impl<'a> HttpApiBuilder<'a> {
|
||||
HttpApiBuilder {
|
||||
gateway_config,
|
||||
network_requester_config: None,
|
||||
ip_packet_router_config: None,
|
||||
exit_policy: None,
|
||||
identity_keypair,
|
||||
sphinx_keypair,
|
||||
@@ -187,6 +228,15 @@ impl<'a> HttpApiBuilder<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn with_maybe_ip_packet_router(
|
||||
mut self,
|
||||
ip_packet_router_config: Option<&'a nym_ip_packet_router::Config>,
|
||||
) -> Self {
|
||||
self.ip_packet_router_config = ip_packet_router_config;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn with_wireguard_client_registry(
|
||||
mut self,
|
||||
@@ -225,6 +275,13 @@ impl<'a> HttpApiBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ipr_config) = self.ip_packet_router_config {
|
||||
config = config.with_ip_packet_router(load_ip_packet_router_details(
|
||||
self.gateway_config,
|
||||
ipr_config,
|
||||
)?);
|
||||
}
|
||||
|
||||
let wireguard_private_network = IpNetwork::new(
|
||||
IpAddr::from(Ipv4Addr::new(10, 1, 0, 0)),
|
||||
self.gateway_config.wireguard.private_network_prefix,
|
||||
|
||||
@@ -8,7 +8,9 @@ use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
use nym_pemstore::KeyPairPath;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_types::gateway::{GatewayNetworkRequesterDetails, GatewayNodeDetailsResponse};
|
||||
use nym_types::gateway::{
|
||||
GatewayIpPacketRouterDetails, GatewayNetworkRequesterDetails, GatewayNodeDetailsResponse,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
fn display_maybe_path<P: AsRef<Path>>(path: Option<P>) -> String {
|
||||
@@ -71,6 +73,40 @@ pub(crate) fn node_details(config: &Config) -> Result<GatewayNodeDetailsResponse
|
||||
None
|
||||
};
|
||||
|
||||
let ip_packet_router = if let Some(nr_cfg_path) = &config.storage_paths.ip_packet_router_config
|
||||
{
|
||||
let cfg = load_ip_packet_router_config(&config.gateway.id, nr_cfg_path)?;
|
||||
|
||||
let nr_identity_public_key: identity::PublicKey = load_public_key(
|
||||
&cfg.storage_paths.common_paths.keys.public_identity_key_file,
|
||||
"ip packet router identity",
|
||||
)?;
|
||||
|
||||
let nr_encryption_key: encryption::PublicKey = load_public_key(
|
||||
&cfg.storage_paths
|
||||
.common_paths
|
||||
.keys
|
||||
.public_encryption_key_file,
|
||||
"ip packet router encryption",
|
||||
)?;
|
||||
|
||||
let address = Recipient::new(
|
||||
nr_identity_public_key,
|
||||
nr_encryption_key,
|
||||
gateway_identity_public_key,
|
||||
);
|
||||
|
||||
Some(GatewayIpPacketRouterDetails {
|
||||
enabled: config.ip_packet_router.enabled,
|
||||
identity_key: nr_identity_public_key.to_base58_string(),
|
||||
encryption_key: nr_encryption_key.to_base58_string(),
|
||||
address: address.to_string(),
|
||||
config_path: display_path(nr_cfg_path),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(GatewayNodeDetailsResponse {
|
||||
identity_key: gateway_identity_public_key.to_base58_string(),
|
||||
sphinx_key: gateway_sphinx_public_key.to_base58_string(),
|
||||
@@ -80,6 +116,7 @@ pub(crate) fn node_details(config: &Config) -> Result<GatewayNodeDetailsResponse
|
||||
config_path: display_maybe_path(config.save_path.as_ref()),
|
||||
data_store: display_path(&config.storage_paths.clients_storage),
|
||||
network_requester,
|
||||
ip_packet_router,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -519,6 +519,7 @@ impl<St> Gateway<St> {
|
||||
.with_wireguard_client_registry(self.client_registry.clone())
|
||||
.with_maybe_network_requester(self.network_requester_opts.as_ref().map(|o| &o.config))
|
||||
.with_maybe_network_request_filter(nr_request_filter)
|
||||
.with_maybe_ip_packet_router(self.ip_packet_router_opts.as_ref().map(|o| &o.config))
|
||||
.start(shutdown.subscribe().named("http-api"))?;
|
||||
|
||||
// Once this is a bit more mature, make this a commandline flag instead of a compile time
|
||||
|
||||
@@ -366,6 +366,9 @@ pub struct NymNodeDescription {
|
||||
#[serde(default)]
|
||||
pub network_requester: Option<NetworkRequesterDetails>,
|
||||
|
||||
#[serde(default)]
|
||||
pub ip_packet_router: Option<IpPacketRouterDetails>,
|
||||
|
||||
// for now we only care about their ws/wss situation, nothing more
|
||||
pub mixnet_websockets: WebSockets,
|
||||
}
|
||||
@@ -393,3 +396,9 @@ pub struct NetworkRequesterDetails {
|
||||
/// flag indicating whether this network requester uses the exit policy rather than the deprecated allow list
|
||||
pub uses_exit_policy: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
|
||||
pub struct IpPacketRouterDetails {
|
||||
/// address of the embedded ip packet router
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
@@ -14,14 +14,13 @@ use crate::coconut::keypair::KeyPair as CoconutKeyPair;
|
||||
use crate::nyxd;
|
||||
use crate::support::config;
|
||||
use anyhow::Result;
|
||||
use nym_coconut_dkg_common::types::{Epoch, EpochState};
|
||||
use nym_coconut_dkg_common::types::EpochState;
|
||||
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use tokio::time::interval;
|
||||
|
||||
pub(crate) fn init_keypair(config: &config::CoconutSigner) -> Result<()> {
|
||||
@@ -98,121 +97,99 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn maybe_advance_dkg_state(&self, epoch: Epoch) {
|
||||
let end =
|
||||
OffsetDateTime::from_unix_timestamp(epoch.finish_timestamp.seconds() as i64).unwrap();
|
||||
|
||||
let remaining = end - OffsetDateTime::now_utc();
|
||||
|
||||
// TODO: after debugging is finished, change that to `debug!`
|
||||
info!(
|
||||
"there are {} seconds until the current DKG epoch [stage] end",
|
||||
remaining.whole_seconds()
|
||||
);
|
||||
|
||||
if remaining.is_negative() {
|
||||
// We try advancing the epoch state, on a best-effort basis
|
||||
info!("DKG: Trying to advance the epoch");
|
||||
if let Err(err) = self.dkg_client.advance_epoch_state().await {
|
||||
error!("failed to advance DKG epoch: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn handle_epoch_state(&mut self) {
|
||||
let epoch = match self.dkg_client.get_current_epoch().await {
|
||||
Ok(epoch) => epoch,
|
||||
Err(err) => {
|
||||
warn!("Could not get current epoch state: {err}");
|
||||
return;
|
||||
match self.dkg_client.get_current_epoch().await {
|
||||
Err(err) => warn!("Could not get current epoch state {err}"),
|
||||
Ok(epoch) => {
|
||||
if self
|
||||
.dkg_client
|
||||
.group_member()
|
||||
.await
|
||||
.map(|resp| resp.weight.is_none())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
debug!("Not a member of the group, DKG won't be run");
|
||||
return;
|
||||
}
|
||||
if let Err(err) = self.state.is_consistent(epoch.state).await {
|
||||
debug!("Epoch state is corrupted - {err}. Awaiting for a DKG restart.");
|
||||
} else {
|
||||
let ret = match epoch.state {
|
||||
EpochState::PublicKeySubmission { resharing } => {
|
||||
public_key_submission(&self.dkg_client, &mut self.state, resharing)
|
||||
.await
|
||||
}
|
||||
EpochState::DealingExchange { resharing } => {
|
||||
dealing_exchange(
|
||||
&self.dkg_client,
|
||||
&mut self.state,
|
||||
self.rng.clone(),
|
||||
resharing,
|
||||
)
|
||||
.await
|
||||
}
|
||||
EpochState::VerificationKeySubmission { resharing } => {
|
||||
let keypair_path = nym_pemstore::KeyPairPath::new(
|
||||
self.secret_key_path.clone(),
|
||||
self.verification_key_path.clone(),
|
||||
);
|
||||
verification_key_submission(
|
||||
&self.dkg_client,
|
||||
&mut self.state,
|
||||
&keypair_path,
|
||||
resharing,
|
||||
)
|
||||
.await
|
||||
}
|
||||
EpochState::VerificationKeyValidation { resharing } => {
|
||||
verification_key_validation(
|
||||
&self.dkg_client,
|
||||
&mut self.state,
|
||||
resharing,
|
||||
)
|
||||
.await
|
||||
}
|
||||
EpochState::VerificationKeyFinalization { resharing } => {
|
||||
verification_key_finalization(
|
||||
&self.dkg_client,
|
||||
&mut self.state,
|
||||
resharing,
|
||||
)
|
||||
.await
|
||||
}
|
||||
// Just wait, in case we need to redo dkg at some point
|
||||
EpochState::InProgress => {
|
||||
self.state.set_was_in_progress();
|
||||
// We're dumping state here so that we don't do it uselessly during the
|
||||
// long InProgress state
|
||||
self.dump_persistent_state().await;
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
if let Err(err) = ret {
|
||||
warn!("Could not handle this iteration for the epoch state: {err}");
|
||||
} else if epoch.state != EpochState::InProgress {
|
||||
self.dump_persistent_state().await;
|
||||
}
|
||||
}
|
||||
if let Ok(current_timestamp) =
|
||||
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
|
||||
{
|
||||
if current_timestamp.as_secs() >= epoch.finish_timestamp.seconds() {
|
||||
// We try advancing the epoch state, on a best-effort basis
|
||||
info!("DKG: Trying to advance the epoch");
|
||||
self.dkg_client.advance_epoch_state().await.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if self
|
||||
.dkg_client
|
||||
.group_member()
|
||||
.await
|
||||
.map(|resp| resp.weight.is_none())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
debug!("Not a member of the group, DKG won't be run");
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(err) = self.state.is_consistent(epoch.state).await {
|
||||
warn!("Epoch state is corrupted - {err}. Awaiting for a DKG restart.");
|
||||
self.maybe_advance_dkg_state(epoch).await;
|
||||
return;
|
||||
}
|
||||
|
||||
let ret = match epoch.state {
|
||||
EpochState::PublicKeySubmission { resharing } => {
|
||||
info!("attempting to perform DKG key submission");
|
||||
public_key_submission(&self.dkg_client, &mut self.state, resharing).await
|
||||
}
|
||||
EpochState::DealingExchange { resharing } => {
|
||||
info!("attempting to perform DKG dealing exchange");
|
||||
dealing_exchange(
|
||||
&self.dkg_client,
|
||||
&mut self.state,
|
||||
self.rng.clone(),
|
||||
resharing,
|
||||
)
|
||||
.await
|
||||
}
|
||||
EpochState::VerificationKeySubmission { resharing } => {
|
||||
info!("attempting to perform DKG verification key submission");
|
||||
let keypair_path = nym_pemstore::KeyPairPath::new(
|
||||
self.secret_key_path.clone(),
|
||||
self.verification_key_path.clone(),
|
||||
);
|
||||
verification_key_submission(
|
||||
&self.dkg_client,
|
||||
&mut self.state,
|
||||
&keypair_path,
|
||||
resharing,
|
||||
)
|
||||
.await
|
||||
}
|
||||
EpochState::VerificationKeyValidation { resharing } => {
|
||||
info!("attempting to perform DKG verification key validation");
|
||||
verification_key_validation(&self.dkg_client, &mut self.state, resharing).await
|
||||
}
|
||||
EpochState::VerificationKeyFinalization { resharing } => {
|
||||
info!("attempting to perform DKG verification key finalization");
|
||||
verification_key_finalization(&self.dkg_client, &mut self.state, resharing).await
|
||||
}
|
||||
// Just wait, in case we need to redo dkg at some point
|
||||
EpochState::InProgress => {
|
||||
info!(
|
||||
"DKG epoch is in progress - dumping the persistent state to {}",
|
||||
self.state.persistent_state_path().display()
|
||||
);
|
||||
|
||||
self.state.set_was_in_progress();
|
||||
// We're dumping state here so that we don't do it uselessly during the
|
||||
// long InProgress state
|
||||
self.dump_persistent_state().await;
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
if let Err(err) = ret {
|
||||
warn!("Could not handle this iteration for the epoch state: {err}");
|
||||
} else if epoch.state != EpochState::InProgress {
|
||||
self.dump_persistent_state().await;
|
||||
}
|
||||
|
||||
self.maybe_advance_dkg_state(epoch).await
|
||||
}
|
||||
|
||||
pub(crate) async fn run(mut self, mut shutdown: TaskClient) {
|
||||
let mut interval = interval(self.polling_rate);
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.tick() => {
|
||||
info!("DkgController tick (this should be happening every {:?}", self.polling_rate);
|
||||
self.handle_epoch_state().await
|
||||
}
|
||||
_ = interval.tick() => self.handle_epoch_state().await,
|
||||
_ = shutdown.recv() => {
|
||||
trace!("DkgController: Received shutdown");
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ use crate::support::caching::refresher::{CacheItemProvider, CacheRefresher};
|
||||
use crate::support::config;
|
||||
use crate::support::config::DEFAULT_NODE_DESCRIBE_BATCH_SIZE;
|
||||
use futures_util::{stream, StreamExt};
|
||||
use nym_api_requests::models::{NetworkRequesterDetails, NymNodeDescription};
|
||||
use nym_api_requests::models::{
|
||||
IpPacketRouterDetails, NetworkRequesterDetails, NymNodeDescription,
|
||||
};
|
||||
use nym_config::defaults::{mainnet, DEFAULT_NYM_NODE_HTTP_PORT};
|
||||
use nym_contracts_common::IdentityKey;
|
||||
use nym_mixnet_contract_common::Gateway;
|
||||
@@ -170,10 +172,19 @@ async fn get_gateway_description(
|
||||
None
|
||||
};
|
||||
|
||||
let ip_packet_router = if let Ok(ipr) = client.get_ip_packet_router().await {
|
||||
Some(IpPacketRouterDetails {
|
||||
address: ipr.address,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let description = NymNodeDescription {
|
||||
host_information: host_info.data,
|
||||
build_information: build_info,
|
||||
network_requester,
|
||||
ip_packet_router,
|
||||
mixnet_websockets: websockets,
|
||||
};
|
||||
|
||||
|
||||
@@ -375,7 +375,7 @@ impl crate::coconut::client::Client for Client {
|
||||
fee: Option<Fee>,
|
||||
) -> Result<(), CoconutError> {
|
||||
self.0
|
||||
.read()
|
||||
.write()
|
||||
.await
|
||||
.vote_proposal(proposal_id, vote_yes, fee)
|
||||
.await?;
|
||||
@@ -384,7 +384,7 @@ impl crate::coconut::client::Client for Client {
|
||||
|
||||
async fn execute_proposal(&self, proposal_id: u64) -> crate::coconut::error::Result<()> {
|
||||
self.0
|
||||
.read()
|
||||
.write()
|
||||
.await
|
||||
.execute_proposal(proposal_id, None)
|
||||
.await?;
|
||||
|
||||
@@ -11,6 +11,7 @@ use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use nym_wireguard_types::{ClientMessage, ClientRegistrationResponse};
|
||||
|
||||
use crate::api::v1::health::models::NodeHealth;
|
||||
use crate::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
use crate::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
|
||||
use crate::api::v1::network_requester::models::NetworkRequester;
|
||||
pub use http_api_client::Client;
|
||||
@@ -54,6 +55,11 @@ pub trait NymNodeApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_ip_packet_router(&self) -> Result<IpPacketRouter, NymNodeApiClientError> {
|
||||
self.get_json_from(routes::api::v1::ip_packet_router_absolute())
|
||||
.await
|
||||
}
|
||||
|
||||
async fn post_gateway_register_client(
|
||||
&self,
|
||||
client_message: &ClientMessage,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod models;
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct IpPacketRouter {
|
||||
/// Base58 encoded ed25519 EdDSA public key of the ip-packet-router.
|
||||
pub encoded_identity_key: String,
|
||||
|
||||
/// Base58-encoded x25519 public key used for performing key exchange with remote clients.
|
||||
pub encoded_x25519_key: String,
|
||||
|
||||
/// Nym address of this ip packet router.
|
||||
pub address: String,
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
pub mod gateway;
|
||||
pub mod health;
|
||||
pub mod ip_packet_router;
|
||||
pub mod mixnode;
|
||||
pub mod network_requester;
|
||||
pub mod node;
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct NodeRoles {
|
||||
pub mixnode_enabled: bool,
|
||||
pub gateway_enabled: bool,
|
||||
pub network_requester_enabled: bool,
|
||||
pub ip_packet_router_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
|
||||
@@ -33,6 +33,7 @@ pub mod routes {
|
||||
pub const GATEWAY: &str = "/gateway";
|
||||
pub const MIXNODE: &str = "/mixnode";
|
||||
pub const NETWORK_REQUESTER: &str = "/network-requester";
|
||||
pub const IP_PACKET_ROUTER: &str = "/ip-packet-router";
|
||||
pub const SWAGGER: &str = "/swagger";
|
||||
|
||||
// define helper functions to get absolute routes
|
||||
@@ -43,6 +44,7 @@ pub mod routes {
|
||||
absolute_route!(gateway_absolute, v1_absolute(), GATEWAY);
|
||||
absolute_route!(mixnode_absolute, v1_absolute(), MIXNODE);
|
||||
absolute_route!(network_requester_absolute, v1_absolute(), NETWORK_REQUESTER);
|
||||
absolute_route!(ip_packet_router_absolute, v1_absolute(), IP_PACKET_ROUTER);
|
||||
absolute_route!(swagger_absolute, v1_absolute(), SWAGGER);
|
||||
|
||||
pub mod gateway {
|
||||
@@ -96,6 +98,10 @@ pub mod routes {
|
||||
EXIT_POLICY
|
||||
);
|
||||
}
|
||||
|
||||
pub mod ip_packet_router {
|
||||
// use super::*;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,5 +152,9 @@ mod tests {
|
||||
"/api/v1/network-requester",
|
||||
routes::api::v1::network_requester_absolute()
|
||||
);
|
||||
assert_eq!(
|
||||
"/api/v1/ip-packet-router",
|
||||
routes::api::v1::ip_packet_router_absolute()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use nym_node_requests::api::v1::ip_packet_router::models;
|
||||
|
||||
pub mod root;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Config {
|
||||
pub details: Option<models::IpPacketRouter>,
|
||||
}
|
||||
|
||||
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router<S> {
|
||||
Router::new().route(
|
||||
"/",
|
||||
get({
|
||||
let ip_packet_router_details = config.details;
|
||||
move |query| root::root_ip_packet_router(ip_packet_router_details, query)
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::http::router::api::{FormattedResponse, OutputParams};
|
||||
use axum::extract::Query;
|
||||
use axum::http::StatusCode;
|
||||
use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
|
||||
/// Returns root network requester information
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/ip-packet-router",
|
||||
tag = "IP Packet Router",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
("application/json" = IpPacketRouter),
|
||||
("application/yaml" = IpPacketRouter)
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_ip_packet_router(
|
||||
details: Option<IpPacketRouter>,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> Result<IpPacketRouterResponse, StatusCode> {
|
||||
let details = details.ok_or(StatusCode::NOT_IMPLEMENTED)?;
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(details))
|
||||
}
|
||||
|
||||
pub type IpPacketRouterResponse = FormattedResponse<IpPacketRouter>;
|
||||
@@ -9,6 +9,7 @@ use nym_node_requests::routes::api::v1;
|
||||
|
||||
pub mod gateway;
|
||||
pub mod health;
|
||||
pub mod ip_packet_router;
|
||||
pub mod mixnode;
|
||||
pub mod network_requester;
|
||||
pub mod node;
|
||||
@@ -20,6 +21,7 @@ pub struct Config {
|
||||
pub gateway: gateway::Config,
|
||||
pub mixnode: mixnode::Config,
|
||||
pub network_requester: network_requester::Config,
|
||||
pub ip_packet_router: ip_packet_router::Config,
|
||||
}
|
||||
|
||||
pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Router<AppState> {
|
||||
@@ -34,6 +36,10 @@ pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Rou
|
||||
v1::NETWORK_REQUESTER,
|
||||
network_requester::routes(config.network_requester),
|
||||
)
|
||||
.nest(
|
||||
v1::IP_PACKET_ROUTER,
|
||||
ip_packet_router::routes(config.ip_packet_router),
|
||||
)
|
||||
.merge(node::routes(config.node))
|
||||
.merge(openapi::route())
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
api::v1::mixnode::root::root_mixnode,
|
||||
api::v1::network_requester::root::root_network_requester,
|
||||
api::v1::network_requester::exit_policy::node_exit_policy,
|
||||
api::v1::ip_packet_router::root::root_ip_packet_router,
|
||||
),
|
||||
components(
|
||||
schemas(
|
||||
@@ -56,6 +57,7 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
api_requests::v1::network_requester::exit_policy::models::AddressPortPattern,
|
||||
api_requests::v1::network_requester::exit_policy::models::PortRange,
|
||||
api_requests::v1::network_requester::exit_policy::models::UsedExitPolicy,
|
||||
api_requests::v1::ip_packet_router::models::IpPacketRouter,
|
||||
),
|
||||
responses(RequestError)
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::http::state::AppState;
|
||||
use crate::http::NymNodeHTTPServer;
|
||||
use axum::Router;
|
||||
use nym_node_requests::api::v1::gateway::models::{Gateway, Wireguard};
|
||||
use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
use nym_node_requests::api::v1::mixnode::models::Mixnode;
|
||||
use nym_node_requests::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
|
||||
use nym_node_requests::api::v1::network_requester::models::NetworkRequester;
|
||||
@@ -45,6 +46,7 @@ impl Config {
|
||||
gateway: Default::default(),
|
||||
mixnode: Default::default(),
|
||||
network_requester: Default::default(),
|
||||
ip_packet_router: Default::default(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -94,6 +96,13 @@ impl Config {
|
||||
self.api.v1_config.network_requester.exit_policy = Some(exit_policy);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_ip_packet_router(mut self, ip_packet_router: IpPacketRouter) -> Self {
|
||||
self.api.v1_config.node.roles.ip_packet_router_enabled = true;
|
||||
self.api.v1_config.ip_packet_router.details = Some(ip_packet_router);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NymNodeRouter {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { RadioGroup } from '@headlessui/react';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import clsx from 'clsx';
|
||||
@@ -16,6 +16,12 @@ function NetworkModeSelect() {
|
||||
|
||||
const { t } = useTranslation('home');
|
||||
|
||||
useEffect(() => {
|
||||
if (state.vpnMode !== selected) {
|
||||
setSelected(state.vpnMode);
|
||||
}
|
||||
}, [state.vpnMode, selected]);
|
||||
|
||||
const handleNetworkModeChange = async (value: VpnMode) => {
|
||||
if (state.state === 'Disconnected' && value !== state.vpnMode) {
|
||||
setLoading(true);
|
||||
|
||||
Generated
+3
-2
@@ -490,9 +490,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3566,6 +3566,7 @@ dependencies = [
|
||||
"nym-crypto",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"x25519-dalek 2.0.0",
|
||||
]
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ pub const REMOTE_SOURCE_OF_NYXD_URLS: &str =
|
||||
|
||||
const CURRENT_GLOBAL_CONFIG_VERSION: u32 = 1;
|
||||
const CURRENT_NETWORK_CONFIG_VERSION: u32 = 1;
|
||||
pub(crate) const CUSTOM_SIMULATED_GAS_MULTIPLIER: f32 = 1.4;
|
||||
pub(crate) const CUSTOM_SIMULATED_GAS_MULTIPLIER: f32 = 1.5;
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct Config {
|
||||
|
||||
@@ -32,6 +32,6 @@ pub async fn simulate_update_contract_settings(
|
||||
vec![],
|
||||
)?;
|
||||
|
||||
let result = client.nyxd.simulate(vec![msg]).await?;
|
||||
let result = client.nyxd.simulate(vec![msg], "").await?;
|
||||
guard.create_detailed_fee(result)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::str::FromStr;
|
||||
pub async fn simulate_send(
|
||||
address: &str,
|
||||
amount: DecCoin,
|
||||
memo: String,
|
||||
state: tauri::State<'_, WalletState>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
@@ -30,7 +31,7 @@ pub async fn simulate_send(
|
||||
amount,
|
||||
};
|
||||
|
||||
let result = client.nyxd.simulate(vec![msg]).await?;
|
||||
let result = client.nyxd.simulate(vec![msg], memo).await?;
|
||||
guard.create_detailed_fee(result)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ async fn simulate_mixnet_operation(
|
||||
.nyxd
|
||||
.wrap_contract_execute_message(mixnet_contract, &msg, funds)?;
|
||||
|
||||
let result = client.nyxd.simulate(vec![msg]).await?;
|
||||
let result = client.nyxd.simulate(vec![msg], "").await?;
|
||||
guard.create_detailed_fee(result)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ async fn simulate_vesting_operation(
|
||||
.nyxd
|
||||
.wrap_contract_execute_message(vesting_contract, &msg, funds)?;
|
||||
|
||||
let result = client.nyxd.simulate(vec![msg]).await?;
|
||||
let result = client.nyxd.simulate(vec![msg], "").await?;
|
||||
guard.create_detailed_fee(result)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import * as Yup from 'yup';
|
||||
import { isLessThan, isValidHostname, validateAmount, validateKey, validateRawPort, validateVersion } from 'src/utils';
|
||||
import {
|
||||
isGreaterThan,
|
||||
isLessThan,
|
||||
isValidHostname,
|
||||
validateAmount,
|
||||
validateKey,
|
||||
validateRawPort,
|
||||
validateVersion,
|
||||
} from 'src/utils';
|
||||
|
||||
export const mixnodeValidationSchema = Yup.object().shape({
|
||||
identityKey: Yup.string()
|
||||
@@ -34,18 +42,21 @@ export const mixnodeValidationSchema = Yup.object().shape({
|
||||
});
|
||||
|
||||
const operatingCostAndPmValidation = {
|
||||
profitMargin: Yup.number().required('Profit Percentage is required').min(0).max(100),
|
||||
profitMargin: Yup.number().required('Profit Percentage is required').min(7).max(80),
|
||||
operatorCost: Yup.object().shape({
|
||||
amount: Yup.string()
|
||||
.required('An operating cost is required')
|
||||
// eslint-disable-next-line prefer-arrow-callback
|
||||
.test('valid-operating-cost', 'A valid amount is required (min 40)', async function isValidAmount(this, value) {
|
||||
if (value && (!Number(value) || isLessThan(+value, 40))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
.test(
|
||||
'valid-operating-cost',
|
||||
'A valid amount is required (min 500 - max 2000)',
|
||||
async function isValidAmount(this, value) {
|
||||
if (value && (!Number(value) || isLessThan(+value, 500) || isGreaterThan(+value, 2000))) {
|
||||
return this.createError({ message: 'A valid amount is required (min 500 - max 2000)' });
|
||||
}
|
||||
return true;
|
||||
},
|
||||
),
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const defaultMixnodeValues: MixnodeData = {
|
||||
|
||||
const defaultAmountValues = (denom: CurrencyDenom) => ({
|
||||
amount: { amount: '100', denom },
|
||||
operatorCost: { amount: '40', denom },
|
||||
operatorCost: { amount: '500', denom },
|
||||
profitMargin: '10',
|
||||
tokenPool: 'balance',
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ export const SendModal = ({ onClose, hasStorybookStyles }: { onClose: () => void
|
||||
const [gasError, setGasError] = useState<string>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [userFees, setUserFees] = useState<DecCoin>();
|
||||
const [memo, setMemo] = useState<string>();
|
||||
const [memo, setMemo] = useState<string>('');
|
||||
const [txDetails, setTxDetails] = useState<TTransactionDetails>();
|
||||
const [showMoreOptions, setShowMoreOptions] = useState(false);
|
||||
|
||||
@@ -37,7 +37,7 @@ export const SendModal = ({ onClose, hasStorybookStyles }: { onClose: () => void
|
||||
useEffect(() => {
|
||||
if (!showMoreOptions) {
|
||||
setUserFees(undefined);
|
||||
setMemo(undefined);
|
||||
setMemo('');
|
||||
}
|
||||
}, [showMoreOptions]);
|
||||
|
||||
@@ -52,7 +52,7 @@ export const SendModal = ({ onClose, hasStorybookStyles }: { onClose: () => void
|
||||
if (userFees) {
|
||||
await setFeeManually(userFees);
|
||||
} else {
|
||||
await getFee(simulateSend, { address: toAddress, amount });
|
||||
await getFee(simulateSend, { address: toAddress, amount, memo });
|
||||
}
|
||||
setModal('send details');
|
||||
} catch (e) {
|
||||
|
||||
@@ -13,7 +13,12 @@ export const Balance = () => {
|
||||
const { userBalance, clientDetails, network } = useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
userBalance.fetchBalance();
|
||||
const interval = setInterval(() => {
|
||||
userBalance.fetchBalance();
|
||||
userBalance.fetchTokenAllocation();
|
||||
}, 10000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const handleShowTransferModal = async () => {
|
||||
|
||||
@@ -204,7 +204,7 @@ const Bonding = () => {
|
||||
{confirmationDetails && confirmationDetails.status === 'success' && (
|
||||
<ConfirmationDetailsModal
|
||||
title={confirmationDetails.title}
|
||||
subtitle={confirmationDetails.subtitle || 'This operation can take up to one hour to process'}
|
||||
subtitle={confirmationDetails.subtitle}
|
||||
status={confirmationDetails.status}
|
||||
txUrl={confirmationDetails.txUrl}
|
||||
onClose={() => {
|
||||
|
||||
@@ -69,8 +69,8 @@ export const simulateVestingUpdateGatewayConfig = async (update: GatewayConfigUp
|
||||
export const simulateWithdrawVestedCoins = async (args: any) =>
|
||||
invokeWrapper<FeeDetails>('simulate_withdraw_vested_coins', args);
|
||||
|
||||
export const simulateSend = async ({ address, amount }: { address: string; amount: DecCoin }) =>
|
||||
invokeWrapper<FeeDetails>('simulate_send', { address, amount });
|
||||
export const simulateSend = async ({ address, amount, memo }: { address: string; amount: DecCoin; memo: string }) =>
|
||||
invokeWrapper<FeeDetails>('simulate_send', { address, amount, memo });
|
||||
|
||||
export const getCustomFees = async ({ feesAmount }: { feesAmount: DecCoin }) =>
|
||||
invokeWrapper<FeeDetails>('get_custom_fees', { feesAmount });
|
||||
|
||||
Reference in New Issue
Block a user