Merge pull request #5199 from nymtech/merge/release/2024.14-crunch
merge crunch into develop
This commit is contained in:
@@ -4,6 +4,10 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.13-magura-drift] (2024-11-29)
|
||||
|
||||
- Optimised syncing bandwidth information to storage
|
||||
|
||||
## [2024.13-magura-patched] (2024-11-22)
|
||||
|
||||
- [experimental] allow clients to change between deterministic route selection based on packet headers and a pseudorandom distribution
|
||||
|
||||
Generated
+9
-8
@@ -2428,7 +2428,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.42"
|
||||
version = "1.1.43"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.5.20",
|
||||
@@ -4451,7 +4451,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.46"
|
||||
version = "1.1.47"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4701,7 +4701,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.44"
|
||||
version = "1.1.45"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
@@ -4784,7 +4784,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.44"
|
||||
version = "1.1.45"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap 4.5.20",
|
||||
@@ -5892,7 +5892,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -5943,7 +5943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.1.11"
|
||||
version = "1.1.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bip39",
|
||||
@@ -6309,7 +6309,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.44"
|
||||
version = "1.1.45"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap 4.5.20",
|
||||
@@ -6889,6 +6889,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-wireguard-types",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"x25519-dalek",
|
||||
@@ -6911,7 +6912,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.44"
|
||||
version = "1.1.45"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.44"
|
||||
version = "1.1.45"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -111,7 +111,7 @@ impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
async fn sync_storage_bandwidth(&mut self) -> Result<()> {
|
||||
pub async fn sync_storage_bandwidth(&mut self) -> Result<()> {
|
||||
trace!("syncing client bandwidth with the underlying storage");
|
||||
let updated = self
|
||||
.storage
|
||||
|
||||
@@ -8,8 +8,8 @@ use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
const DEFAULT_CLIENT_BANDWIDTH_MAX_FLUSHING_RATE: Duration = Duration::from_millis(5);
|
||||
const DEFAULT_CLIENT_BANDWIDTH_MAX_DELTA_FLUSHING_AMOUNT: i64 = 512 * 1024; // 512kB
|
||||
const DEFAULT_CLIENT_BANDWIDTH_MAX_FLUSHING_RATE: Duration = Duration::from_secs(5 * 60); // 5 minutes
|
||||
const DEFAULT_CLIENT_BANDWIDTH_MAX_DELTA_FLUSHING_AMOUNT: i64 = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BandwidthFlushingBehaviourConfig {
|
||||
|
||||
@@ -212,10 +212,10 @@ impl Add<Polynomial> for Polynomial {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> Add<&'b Polynomial> for &Polynomial {
|
||||
impl<'a> Add<&'a Polynomial> for &Polynomial {
|
||||
type Output = Polynomial;
|
||||
|
||||
fn add(self, rhs: &'b Polynomial) -> Self::Output {
|
||||
fn add(self, rhs: &'a Polynomial) -> Self::Output {
|
||||
let len = self.coefficients.len();
|
||||
let rhs_len = rhs.coefficients.len();
|
||||
|
||||
|
||||
@@ -206,10 +206,10 @@ impl Deref for PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> Mul<&'b Scalar> for &PublicKey {
|
||||
impl<'a> Mul<&'a Scalar> for &PublicKey {
|
||||
type Output = G1Projective;
|
||||
|
||||
fn mul(self, rhs: &'b Scalar) -> Self::Output {
|
||||
fn mul(self, rhs: &'a Scalar) -> Self::Output {
|
||||
self.0 * rhs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Encodoing and decoding node routing information.
|
||||
//! Encoding and decoding node routing information.
|
||||
//!
|
||||
//! This module is responsible for encoding and decoding node routing information, so that
|
||||
//! they could be later put into an appropriate field in a sphinx header.
|
||||
|
||||
@@ -253,6 +253,9 @@ impl Socks5RequestContent {
|
||||
/// Deserialize the request type, connection id, destination address and port,
|
||||
/// and the request body from bytes.
|
||||
///
|
||||
/// The request_flag tells us whether this is a new connection request (`new_connect`),
|
||||
/// an already-established connection we should send up (`new_send`), or
|
||||
/// a request to close an established connection (`new_close`).
|
||||
// connect:
|
||||
// RequestFlag::Connect || CONN_ID || ADDR_LEN || ADDR || <RETURN_ADDR>
|
||||
//
|
||||
|
||||
@@ -26,6 +26,7 @@ log.workspace = true
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
|
||||
tokio-stream = { workspace = true }
|
||||
time = { workspace = true }
|
||||
|
||||
nym-authenticator-requests = { path = "../authenticator-requests" }
|
||||
nym-credential-verification = { path = "../credential-verification" }
|
||||
|
||||
@@ -20,6 +20,7 @@ use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||
pub(crate) mod error;
|
||||
pub mod peer_controller;
|
||||
pub mod peer_handle;
|
||||
pub mod peer_storage_manager;
|
||||
|
||||
pub struct WgApiWrapper {
|
||||
inner: WGApi,
|
||||
@@ -118,7 +119,7 @@ pub async fn start_wireguard<St: nym_gateway_storage::Storage + Clone + 'static>
|
||||
storage
|
||||
.insert_wireguard_peer(peer, bandwidth_manager.is_some())
|
||||
.await?;
|
||||
peer_bandwidth_managers.insert(peer.public_key.clone(), bandwidth_manager);
|
||||
peer_bandwidth_managers.insert(peer.public_key.clone(), (bandwidth_manager, peer.clone()));
|
||||
}
|
||||
wg_api.create_interface()?;
|
||||
let interface_config = InterfaceConfiguration {
|
||||
|
||||
@@ -20,9 +20,9 @@ use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::{mpsc, RwLock};
|
||||
use tokio_stream::{wrappers::IntervalStream, StreamExt};
|
||||
|
||||
use crate::peer_handle::PeerHandle;
|
||||
use crate::WgApiWrapper;
|
||||
use crate::{error::Error, peer_handle::SharedBandwidthStorageManager};
|
||||
use crate::{peer_handle::PeerHandle, peer_storage_manager::PeerStorageManager};
|
||||
|
||||
pub enum PeerControlRequest {
|
||||
AddPeer {
|
||||
@@ -79,7 +79,7 @@ impl<St: Storage + Clone + 'static> PeerController<St> {
|
||||
storage: St,
|
||||
wg_api: Arc<WgApiWrapper>,
|
||||
initial_host_information: Host,
|
||||
bw_storage_managers: HashMap<Key, Option<SharedBandwidthStorageManager<St>>>,
|
||||
bw_storage_managers: HashMap<Key, (Option<SharedBandwidthStorageManager<St>>, Peer)>,
|
||||
request_tx: mpsc::Sender<PeerControlRequest>,
|
||||
request_rx: mpsc::Receiver<PeerControlRequest>,
|
||||
task_client: nym_task::TaskClient,
|
||||
@@ -88,11 +88,16 @@ impl<St: Storage + Clone + 'static> PeerController<St> {
|
||||
tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK),
|
||||
);
|
||||
let host_information = Arc::new(RwLock::new(initial_host_information));
|
||||
for (public_key, bandwidth_storage_manager) in bw_storage_managers.iter() {
|
||||
let mut handle = PeerHandle::new(
|
||||
for (public_key, (bandwidth_storage_manager, peer)) in bw_storage_managers.iter() {
|
||||
let peer_storage_manager = PeerStorageManager::new(
|
||||
storage.clone(),
|
||||
peer.clone(),
|
||||
bandwidth_storage_manager.is_some(),
|
||||
);
|
||||
let mut handle = PeerHandle::new(
|
||||
public_key.clone(),
|
||||
host_information.clone(),
|
||||
peer_storage_manager,
|
||||
bandwidth_storage_manager.clone(),
|
||||
request_tx.clone(),
|
||||
&task_client,
|
||||
@@ -103,6 +108,10 @@ impl<St: Storage + Clone + 'static> PeerController<St> {
|
||||
}
|
||||
});
|
||||
}
|
||||
let bw_storage_managers = bw_storage_managers
|
||||
.into_iter()
|
||||
.map(|(k, (m, _))| (k, m))
|
||||
.collect();
|
||||
|
||||
PeerController {
|
||||
storage,
|
||||
@@ -184,10 +193,15 @@ impl<St: Storage + Clone + 'static> PeerController<St> {
|
||||
Self::generate_bandwidth_manager(self.storage.clone(), &peer.public_key)
|
||||
.await?
|
||||
.map(|bw_m| Arc::new(RwLock::new(bw_m)));
|
||||
let mut handle = PeerHandle::new(
|
||||
let peer_storage_manager = PeerStorageManager::new(
|
||||
self.storage.clone(),
|
||||
peer.clone(),
|
||||
bandwidth_storage_manager.is_some(),
|
||||
);
|
||||
let mut handle = PeerHandle::new(
|
||||
peer.public_key.clone(),
|
||||
self.host_information.clone(),
|
||||
peer_storage_manager,
|
||||
bandwidth_storage_manager.clone(),
|
||||
self.request_tx.clone(),
|
||||
&self.task_client,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::peer_controller::PeerControlRequest;
|
||||
use crate::peer_storage_manager::PeerStorageManager;
|
||||
use defguard_wireguard_rs::host::Peer;
|
||||
use defguard_wireguard_rs::{host::Host, key::Key};
|
||||
use futures::channel::oneshot;
|
||||
@@ -21,9 +22,9 @@ pub(crate) type SharedBandwidthStorageManager<St> = Arc<RwLock<BandwidthStorageM
|
||||
const AUTO_REMOVE_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 30); // 30 days
|
||||
|
||||
pub struct PeerHandle<St> {
|
||||
storage: St,
|
||||
public_key: Key,
|
||||
host_information: Arc<RwLock<Host>>,
|
||||
peer_storage_manager: PeerStorageManager<St>,
|
||||
bandwidth_storage_manager: Option<SharedBandwidthStorageManager<St>>,
|
||||
request_tx: mpsc::Sender<PeerControlRequest>,
|
||||
timeout_check_interval: IntervalStream,
|
||||
@@ -33,9 +34,9 @@ pub struct PeerHandle<St> {
|
||||
|
||||
impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
||||
pub fn new(
|
||||
storage: St,
|
||||
public_key: Key,
|
||||
host_information: Arc<RwLock<Host>>,
|
||||
peer_storage_manager: PeerStorageManager<St>,
|
||||
bandwidth_storage_manager: Option<SharedBandwidthStorageManager<St>>,
|
||||
request_tx: mpsc::Sender<PeerControlRequest>,
|
||||
task_client: &TaskClient,
|
||||
@@ -46,9 +47,9 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
||||
let mut task_client = task_client.fork(format!("peer-{public_key}"));
|
||||
task_client.disarm();
|
||||
PeerHandle {
|
||||
storage,
|
||||
public_key,
|
||||
host_information,
|
||||
peer_storage_manager,
|
||||
bandwidth_storage_manager,
|
||||
request_tx,
|
||||
timeout_check_interval,
|
||||
@@ -84,16 +85,19 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
||||
.ok_or(Error::InconsistentConsumedBytes)?
|
||||
.try_into()
|
||||
.map_err(|_| Error::InconsistentConsumedBytes)?;
|
||||
if spent_bandwidth > 0
|
||||
&& bandwidth_manager
|
||||
if spent_bandwidth > 0 {
|
||||
self.peer_storage_manager.update_trx(kernel_peer);
|
||||
if bandwidth_manager
|
||||
.write()
|
||||
.await
|
||||
.try_use_bandwidth(spent_bandwidth)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
let success = self.remove_peer().await?;
|
||||
return Ok(!success);
|
||||
{
|
||||
let success = self.remove_peer().await?;
|
||||
self.peer_storage_manager.remove_peer();
|
||||
return Ok(!success);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if SystemTime::now().duration_since(self.startup_timestamp)? >= AUTO_REMOVE_AFTER {
|
||||
@@ -132,7 +136,7 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
||||
// the host information hasn't beed updated yet
|
||||
continue;
|
||||
};
|
||||
let Some(storage_peer) = self.storage.get_wireguard_peer(&self.public_key.to_string()).await? else {
|
||||
let Some(storage_peer) = self.peer_storage_manager.get_peer() else {
|
||||
log::debug!("Peer {:?} not in storage anymore, shutting down handle", self.public_key);
|
||||
return Ok(());
|
||||
};
|
||||
@@ -141,12 +145,18 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
||||
return Ok(());
|
||||
} else {
|
||||
// Update storage values
|
||||
self.storage.insert_wireguard_peer(&kernel_peer, self.bandwidth_storage_manager.is_some()).await?;
|
||||
self.peer_storage_manager.sync_storage_peer().await?;
|
||||
}
|
||||
}
|
||||
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("PeerHandle: Received shutdown");
|
||||
if let Some(bandwidth_manager) = &self.bandwidth_storage_manager {
|
||||
if let Err(e) = bandwidth_manager.write().await.sync_storage_bandwidth().await {
|
||||
log::error!("Storage sync failed - {e}, unaccounted bandwidth might have been consumed");
|
||||
}
|
||||
}
|
||||
log::trace!("PeerHandle: Finished shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::Error;
|
||||
use defguard_wireguard_rs::host::Peer;
|
||||
use nym_gateway_storage::models::WireguardPeer;
|
||||
use nym_gateway_storage::Storage;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
const DEFAULT_PEER_MAX_FLUSHING_RATE: Duration = Duration::from_secs(60 * 60 * 24); // 24h
|
||||
const DEFAULT_PEER_MAX_DELTA_FLUSHING_AMOUNT: u64 = 512 * 1024 * 1024; // 512MB
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PeerFlushingBehaviourConfig {
|
||||
/// Defines maximum delay between peer information being flushed to the persistent storage.
|
||||
pub peer_max_flushing_rate: Duration,
|
||||
|
||||
/// Defines a maximum change in peer before it gets flushed to the persistent storage.
|
||||
pub peer_max_delta_flushing_amount: u64,
|
||||
}
|
||||
|
||||
impl Default for PeerFlushingBehaviourConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
peer_max_flushing_rate: DEFAULT_PEER_MAX_FLUSHING_RATE,
|
||||
peer_max_delta_flushing_amount: DEFAULT_PEER_MAX_DELTA_FLUSHING_AMOUNT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PeerStorageManager<S> {
|
||||
pub(crate) storage: S,
|
||||
pub(crate) peer_information: Option<PeerInformation>,
|
||||
pub(crate) cfg: PeerFlushingBehaviourConfig,
|
||||
pub(crate) with_client_id: bool,
|
||||
}
|
||||
|
||||
impl<S: Storage + Clone + 'static> PeerStorageManager<S> {
|
||||
pub(crate) fn new(storage: S, peer: Peer, with_client_id: bool) -> Self {
|
||||
let peer_information = Some(PeerInformation::new(peer));
|
||||
Self {
|
||||
storage,
|
||||
peer_information,
|
||||
cfg: PeerFlushingBehaviourConfig::default(),
|
||||
with_client_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_peer(&self) -> Option<WireguardPeer> {
|
||||
self.peer_information
|
||||
.as_ref()
|
||||
.map(|p| p.peer.clone().into())
|
||||
}
|
||||
|
||||
pub(crate) fn remove_peer(&mut self) {
|
||||
self.peer_information = None;
|
||||
}
|
||||
|
||||
pub(crate) fn update_trx(&mut self, kernel_peer: &Peer) {
|
||||
if let Some(peer_information) = self.peer_information.as_mut() {
|
||||
peer_information.update_trx_bytes(kernel_peer.tx_bytes, kernel_peer.rx_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn sync_storage_peer(&mut self) -> Result<(), Error> {
|
||||
let Some(peer_information) = self.peer_information.as_mut() else {
|
||||
return Ok(());
|
||||
};
|
||||
if !peer_information.should_sync(self.cfg) {
|
||||
return Ok(());
|
||||
}
|
||||
if self
|
||||
.storage
|
||||
.get_wireguard_peer(&peer_information.peer().public_key.to_string())
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
self.peer_information = None;
|
||||
return Ok(());
|
||||
}
|
||||
self.storage
|
||||
.insert_wireguard_peer(peer_information.peer(), self.with_client_id)
|
||||
.await?;
|
||||
|
||||
peer_information.resync_peer_with_storage();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct PeerInformation {
|
||||
pub(crate) peer: Peer,
|
||||
pub(crate) last_synced: OffsetDateTime,
|
||||
|
||||
pub(crate) bytes_delta_since_sync: u64,
|
||||
}
|
||||
|
||||
impl PeerInformation {
|
||||
pub fn new(peer: Peer) -> PeerInformation {
|
||||
PeerInformation {
|
||||
peer,
|
||||
last_synced: OffsetDateTime::now_utc(),
|
||||
bytes_delta_since_sync: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn should_sync(&self, cfg: PeerFlushingBehaviourConfig) -> bool {
|
||||
if self.bytes_delta_since_sync >= cfg.peer_max_delta_flushing_amount {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.last_synced + cfg.peer_max_flushing_rate < OffsetDateTime::now_utc()
|
||||
&& self.bytes_delta_since_sync != 0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn peer(&self) -> &Peer {
|
||||
&self.peer
|
||||
}
|
||||
|
||||
pub(crate) fn update_trx_bytes(&mut self, tx_bytes: u64, rx_bytes: u64) {
|
||||
self.bytes_delta_since_sync += tx_bytes.saturating_sub(self.peer.tx_bytes)
|
||||
+ rx_bytes.saturating_sub(self.peer.rx_bytes);
|
||||
self.peer.tx_bytes = tx_bytes;
|
||||
self.peer.rx_bytes = rx_bytes;
|
||||
}
|
||||
|
||||
pub(crate) fn resync_peer_with_storage(&mut self) {
|
||||
self.bytes_delta_since_sync = 0;
|
||||
self.last_synced = OffsetDateTime::now_utc();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.1.42"
|
||||
version = "1.1.43"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
|
||||
+46
-12
@@ -5,6 +5,8 @@ use async_trait::async_trait;
|
||||
use nym_sdk::{NymApiTopologyProvider, NymApiTopologyProviderConfig, UserAgent};
|
||||
use nym_topology::{gateway, NymTopology, TopologyProvider};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::debug;
|
||||
use url::Url;
|
||||
@@ -17,6 +19,7 @@ pub struct GatewayTopologyProvider {
|
||||
impl GatewayTopologyProvider {
|
||||
pub fn new(
|
||||
gateway_node: gateway::LegacyNode,
|
||||
cache_ttl: Duration,
|
||||
user_agent: UserAgent,
|
||||
nym_api_url: Vec<Url>,
|
||||
) -> GatewayTopologyProvider {
|
||||
@@ -31,6 +34,9 @@ impl GatewayTopologyProvider {
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
Some(user_agent),
|
||||
),
|
||||
cache_ttl,
|
||||
cached_at: OffsetDateTime::UNIX_EPOCH,
|
||||
cached: None,
|
||||
gateway_node,
|
||||
})),
|
||||
}
|
||||
@@ -39,25 +45,53 @@ impl GatewayTopologyProvider {
|
||||
|
||||
struct GatewayTopologyProviderInner {
|
||||
inner: NymApiTopologyProvider,
|
||||
cache_ttl: Duration,
|
||||
cached_at: OffsetDateTime,
|
||||
cached: Option<NymTopology>,
|
||||
gateway_node: gateway::LegacyNode,
|
||||
}
|
||||
|
||||
impl GatewayTopologyProviderInner {
|
||||
fn cached_topology(&self) -> Option<NymTopology> {
|
||||
if let Some(cached_topology) = &self.cached {
|
||||
if self.cached_at + self.cache_ttl > OffsetDateTime::now_utc() {
|
||||
return Some(cached_topology.clone());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
async fn update_cache(&mut self) -> Option<NymTopology> {
|
||||
let updated_cache = match self.inner.get_new_topology().await {
|
||||
None => None,
|
||||
Some(mut base) => {
|
||||
if !base.gateway_exists(&self.gateway_node.identity_key) {
|
||||
debug!(
|
||||
"{} didn't exist in topology. inserting it.",
|
||||
self.gateway_node.identity_key
|
||||
);
|
||||
base.insert_gateway(self.gateway_node.clone());
|
||||
}
|
||||
Some(base)
|
||||
}
|
||||
};
|
||||
|
||||
self.cached_at = OffsetDateTime::now_utc();
|
||||
self.cached = updated_cache.clone();
|
||||
|
||||
updated_cache
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TopologyProvider for GatewayTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
let mut guard = self.inner.lock().await;
|
||||
match guard.inner.get_new_topology().await {
|
||||
None => None,
|
||||
Some(mut base) => {
|
||||
if !base.gateway_exists(&guard.gateway_node.identity_key) {
|
||||
debug!(
|
||||
"{} didn't exist in topology. inserting it.",
|
||||
guard.gateway_node.identity_key
|
||||
);
|
||||
base.insert_gateway(guard.gateway_node.clone());
|
||||
}
|
||||
Some(base)
|
||||
}
|
||||
// check the cache
|
||||
if let Some(cached) = guard.cached_topology() {
|
||||
return Some(cached);
|
||||
}
|
||||
guard.update_cache().await
|
||||
}
|
||||
}
|
||||
|
||||
+26
-16
@@ -30,6 +30,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing::*;
|
||||
|
||||
pub(crate) mod client_handling;
|
||||
@@ -148,8 +149,11 @@ impl<St> Gateway<St> {
|
||||
}
|
||||
|
||||
fn gateway_topology_provider(&self) -> GatewayTopologyProvider {
|
||||
// TODO: make topology ttl configurable
|
||||
// (to be done in reeses with the final smooshing)
|
||||
GatewayTopologyProvider::new(
|
||||
self.as_topology_node(),
|
||||
Duration::from_secs(5 * 60),
|
||||
self.user_agent.clone(),
|
||||
self.config.gateway.nym_api_urls.clone(),
|
||||
)
|
||||
@@ -231,22 +235,28 @@ impl<St> Gateway<St> {
|
||||
forwarding_channel,
|
||||
router_tx,
|
||||
);
|
||||
let all_peers = self.client_storage.get_all_wireguard_peers().await?;
|
||||
let used_private_network_ips = all_peers
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|wireguard_peer| {
|
||||
defguard_wireguard_rs::host::Peer::try_from(wireguard_peer).map(|mut peer| {
|
||||
peer.allowed_ips
|
||||
.pop()
|
||||
.ok_or(Box::new(GatewayError::InternalWireguardError(format!(
|
||||
"no private IP set for peer {}",
|
||||
peer.public_key
|
||||
))))
|
||||
.map(|p| p.ip)
|
||||
})
|
||||
})
|
||||
.collect::<Result<Result<Vec<_>, _>, _>>()??;
|
||||
let mut used_private_network_ips = vec![];
|
||||
let mut all_peers = vec![];
|
||||
for wireguard_peer in self
|
||||
.client_storage
|
||||
.get_all_wireguard_peers()
|
||||
.await?
|
||||
.into_iter()
|
||||
{
|
||||
let mut peer = defguard_wireguard_rs::host::Peer::try_from(wireguard_peer.clone())?;
|
||||
let Some(peer) = peer.allowed_ips.pop() else {
|
||||
tracing::warn!(
|
||||
"Peer {} has empty allowed ips. It will be removed",
|
||||
peer.public_key
|
||||
);
|
||||
self.client_storage
|
||||
.remove_wireguard_peer(&peer.public_key.to_string())
|
||||
.await?;
|
||||
continue;
|
||||
};
|
||||
used_private_network_ips.push(peer.ip);
|
||||
all_peers.push(wireguard_peer);
|
||||
}
|
||||
|
||||
if let Some(wireguard_data) = self.wireguard_data.take() {
|
||||
let (on_start_tx, on_start_rx) = oneshot::channel();
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-api"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.46"
|
||||
version = "1.1.47"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
rust-version.workspace = true
|
||||
@@ -121,7 +121,7 @@ nym-types = { path = "../common/types" }
|
||||
nym-http-api-common = { path = "../common/http-api-common", features = ["utoipa"] }
|
||||
nym-serde-helpers = { path = "../common/serde-helpers", features = ["date"] }
|
||||
nym-ticketbooks-merkle = { path = "../common/ticketbooks-merkle" }
|
||||
nym-statistics-common = {path ="../common/statistics" }
|
||||
nym-statistics-common = { path = "../common/statistics" }
|
||||
|
||||
[features]
|
||||
no-reward = []
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
CREATE INDEX IF NOT EXISTS monitor_run_id on monitor_run(id);
|
||||
CREATE INDEX IF NOT EXISTS monitor_run_timestamp on monitor_run(timestamp);
|
||||
CREATE INDEX IF NOT EXISTS testing_route_monitor_run_id on testing_route(monitor_run_id);
|
||||
@@ -6,7 +6,7 @@ use crate::ecash::error::EcashError;
|
||||
use crate::ecash::state::EcashState;
|
||||
use crate::node_status_api::models::AxumResult;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::Path;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::{Json, Router};
|
||||
use nym_api_requests::ecash::models::{
|
||||
AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse,
|
||||
@@ -21,28 +21,19 @@ use tracing::trace;
|
||||
use utoipa::IntoParams;
|
||||
|
||||
/// routes with globally aggregated keys, signatures, etc.
|
||||
pub(crate) fn aggregation_routes(ecash_state: Arc<EcashState>) -> Router<AppState> {
|
||||
pub(crate) fn aggregation_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/master-verification-key",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|epoch_id| master_verification_key(epoch_id, ecash_state)
|
||||
}),
|
||||
axum::routing::get(master_verification_key),
|
||||
)
|
||||
.route(
|
||||
"/aggregated-expiration-date-signatures",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|expiration_date| expiration_date_signatures(expiration_date, ecash_state)
|
||||
}),
|
||||
axum::routing::get(expiration_date_signatures),
|
||||
)
|
||||
.route(
|
||||
"/aggregated-coin-indices-signatures",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|epoch_id| coin_indices_signatures(epoch_id, ecash_state)
|
||||
}),
|
||||
axum::routing::get(coin_indices_signatures),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -58,8 +49,8 @@ pub(crate) fn aggregation_routes(ecash_state: Arc<EcashState>) -> Router<AppStat
|
||||
)
|
||||
)]
|
||||
async fn master_verification_key(
|
||||
Path(EpochIdParam { epoch_id }): Path<EpochIdParam>,
|
||||
state: Arc<EcashState>,
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Query(EpochIdParam { epoch_id }): Query<EpochIdParam>,
|
||||
) -> AxumResult<Json<VerificationKeyResponse>> {
|
||||
trace!("aggregated_verification_key request");
|
||||
|
||||
@@ -72,7 +63,6 @@ async fn master_verification_key(
|
||||
}
|
||||
|
||||
#[derive(Deserialize, IntoParams)]
|
||||
#[into_params(parameter_in = Path)]
|
||||
struct ExpirationDateParam {
|
||||
expiration_date: Option<String>,
|
||||
}
|
||||
@@ -89,8 +79,8 @@ struct ExpirationDateParam {
|
||||
)
|
||||
)]
|
||||
async fn expiration_date_signatures(
|
||||
Path(ExpirationDateParam { expiration_date }): Path<ExpirationDateParam>,
|
||||
state: Arc<EcashState>,
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Query(ExpirationDateParam { expiration_date }): Query<ExpirationDateParam>,
|
||||
) -> AxumResult<Json<AggregatedExpirationDateSignatureResponse>> {
|
||||
trace!("aggregated_expiration_date_signatures request");
|
||||
|
||||
@@ -126,8 +116,8 @@ async fn expiration_date_signatures(
|
||||
)
|
||||
)]
|
||||
async fn coin_indices_signatures(
|
||||
Path(EpochIdParam { epoch_id }): Path<EpochIdParam>,
|
||||
state: Arc<EcashState>,
|
||||
Query(EpochIdParam { epoch_id }): Query<EpochIdParam>,
|
||||
State(state): State<Arc<EcashState>>,
|
||||
) -> AxumResult<Json<AggregatedCoinIndicesSignatureResponse>> {
|
||||
trace!("aggregated_coin_indices_signatures request");
|
||||
|
||||
|
||||
@@ -5,15 +5,13 @@ use crate::ecash::api_routes::aggregation::aggregation_routes;
|
||||
use crate::ecash::api_routes::issued::issued_routes;
|
||||
use crate::ecash::api_routes::partial_signing::partial_signing_routes;
|
||||
use crate::ecash::api_routes::spending::spending_routes;
|
||||
use crate::ecash::state::EcashState;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::Router;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) fn ecash_routes(ecash_state: Arc<EcashState>) -> Router<AppState> {
|
||||
pub(crate) fn ecash_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.merge(aggregation_routes(Arc::clone(&ecash_state)))
|
||||
.merge(issued_routes(Arc::clone(&ecash_state)))
|
||||
.merge(partial_signing_routes(Arc::clone(&ecash_state)))
|
||||
.merge(spending_routes(Arc::clone(&ecash_state)))
|
||||
.merge(aggregation_routes())
|
||||
.merge(issued_routes())
|
||||
.merge(partial_signing_routes())
|
||||
.merge(spending_routes())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#[derive(serde::Deserialize, utoipa::IntoParams)]
|
||||
#[into_params(parameter_in = Path)]
|
||||
pub(super) struct EpochIdParam {
|
||||
pub(super) epoch_id: Option<u64>,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::ecash::state::EcashState;
|
||||
use crate::node_status_api::models::AxumResult;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::Path;
|
||||
use axum::extract::{Path, State};
|
||||
use axum::{Json, Router};
|
||||
use nym_api_requests::ecash::models::{
|
||||
IssuedTicketbooksChallengeRequest, IssuedTicketbooksChallengeResponse,
|
||||
@@ -17,21 +17,15 @@ use time::Date;
|
||||
use tracing::trace;
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
pub(crate) fn issued_routes(ecash_state: Arc<EcashState>) -> Router<AppState> {
|
||||
pub(crate) fn issued_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/issued-ticketbooks-for/:expiration_date",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|expiration_date| issued_ticketbooks_for(expiration_date, ecash_state)
|
||||
}),
|
||||
axum::routing::get(issued_ticketbooks_for),
|
||||
)
|
||||
.route(
|
||||
"/issued-ticketbooks-challenge",
|
||||
axum::routing::post({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|body| issued_ticketbooks_challenge(body, ecash_state)
|
||||
}),
|
||||
axum::routing::post(issued_ticketbooks_challenge),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -58,8 +52,8 @@ pub(crate) struct ExpirationDatePathParam {
|
||||
)
|
||||
)]
|
||||
async fn issued_ticketbooks_for(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Path(ExpirationDatePathParam { expiration_date }): Path<ExpirationDatePathParam>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<IssuedTicketbooksForResponse>> {
|
||||
state.ensure_signer().await?;
|
||||
|
||||
@@ -83,8 +77,8 @@ async fn issued_ticketbooks_for(
|
||||
)
|
||||
)]
|
||||
async fn issued_ticketbooks_challenge(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Json(challenge): Json<IssuedTicketbooksChallengeRequest>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<IssuedTicketbooksChallengeResponse>> {
|
||||
trace!("replying to ticketbooks challenge: {:?}", challenge);
|
||||
state.ensure_signer().await?;
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::ecash::helpers::blind_sign;
|
||||
use crate::ecash::state::EcashState;
|
||||
use crate::node_status_api::models::AxumResult;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::Query;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::{Json, Router};
|
||||
use nym_api_requests::ecash::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse,
|
||||
@@ -22,28 +22,16 @@ use time::Date;
|
||||
use tracing::{debug, trace};
|
||||
use utoipa::IntoParams;
|
||||
|
||||
pub(crate) fn partial_signing_routes(ecash_state: Arc<EcashState>) -> Router<AppState> {
|
||||
pub(crate) fn partial_signing_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/blind-sign",
|
||||
axum::routing::post({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|body| post_blind_sign(body, ecash_state)
|
||||
}),
|
||||
)
|
||||
.route("/blind-sign", axum::routing::post(post_blind_sign))
|
||||
.route(
|
||||
"/partial-expiration-date-signatures",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|expiration_date| partial_expiration_date_signatures(expiration_date, ecash_state)
|
||||
}),
|
||||
axum::routing::get(partial_expiration_date_signatures),
|
||||
)
|
||||
.route(
|
||||
"/partial-coin-indices-signatures",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|epoch_id| partial_coin_indices_signatures(epoch_id, ecash_state)
|
||||
}),
|
||||
axum::routing::get(partial_coin_indices_signatures),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,8 +47,8 @@ pub(crate) fn partial_signing_routes(ecash_state: Arc<EcashState>) -> Router<App
|
||||
)
|
||||
)]
|
||||
async fn post_blind_sign(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Json(blind_sign_request_body): Json<BlindSignRequestBody>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<BlindedSignatureResponse>> {
|
||||
state.ensure_signer().await?;
|
||||
|
||||
@@ -134,8 +122,8 @@ struct ExpirationDateParam {
|
||||
)
|
||||
)]
|
||||
async fn partial_expiration_date_signatures(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Query(ExpirationDateParam { expiration_date }): Query<ExpirationDateParam>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<PartialExpirationDateSignatureResponse>> {
|
||||
state.ensure_signer().await?;
|
||||
|
||||
@@ -172,8 +160,8 @@ async fn partial_expiration_date_signatures(
|
||||
)
|
||||
)]
|
||||
async fn partial_coin_indices_signatures(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
Query(EpochIdParam { epoch_id }): Query<EpochIdParam>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<PartialCoinIndicesSignatureResponse>> {
|
||||
state.ensure_signer().await?;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::ecash::error::EcashError;
|
||||
use crate::ecash::state::EcashState;
|
||||
use crate::node_status_api::models::{AxumErrorResponse, AxumResult};
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::State;
|
||||
use axum::{Json, Router};
|
||||
use nym_api_requests::constants::MIN_BATCH_REDEMPTION_DELAY;
|
||||
use nym_api_requests::ecash::models::{
|
||||
@@ -21,28 +22,16 @@ use time::{OffsetDateTime, Time};
|
||||
use tracing::{error, warn};
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub(crate) fn spending_routes(ecash_state: Arc<EcashState>) -> Router<AppState> {
|
||||
pub(crate) fn spending_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
"/verify-ecash-ticket",
|
||||
axum::routing::post({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|body| verify_ticket(body, ecash_state)
|
||||
}),
|
||||
)
|
||||
.route("/verify-ecash-ticket", axum::routing::post(verify_ticket))
|
||||
.route(
|
||||
"/batch-redeem-ecash-tickets",
|
||||
axum::routing::post({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|body| batch_redeem_tickets(body, ecash_state)
|
||||
}),
|
||||
axum::routing::post(batch_redeem_tickets),
|
||||
)
|
||||
.route(
|
||||
"/double-spending-filter-v1",
|
||||
axum::routing::get({
|
||||
let ecash_state = Arc::clone(&ecash_state);
|
||||
|| double_spending_filter_v1(ecash_state)
|
||||
}),
|
||||
axum::routing::get(double_spending_filter_v1),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -67,9 +56,9 @@ fn reject_ticket(
|
||||
)
|
||||
)]
|
||||
async fn verify_ticket(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
// TODO in the future: make it send binary data rather than json
|
||||
Json(verify_ticket_body): Json<VerifyEcashTicketBody>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<EcashTicketVerificationResponse>> {
|
||||
state.ensure_signer().await?;
|
||||
|
||||
@@ -170,9 +159,9 @@ async fn verify_ticket(
|
||||
)
|
||||
)]
|
||||
async fn batch_redeem_tickets(
|
||||
State(state): State<Arc<EcashState>>,
|
||||
// TODO in the future: make it send binary data rather than json
|
||||
Json(batch_redeem_credentials_body): Json<BatchRedeemTicketsBody>,
|
||||
state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<EcashBatchTicketRedemptionResponse>> {
|
||||
state.ensure_signer().await?;
|
||||
|
||||
@@ -244,8 +233,6 @@ async fn batch_redeem_tickets(
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
async fn double_spending_filter_v1(
|
||||
_state: Arc<EcashState>,
|
||||
) -> AxumResult<Json<SpentCredentialsResponse>> {
|
||||
async fn double_spending_filter_v1() -> AxumResult<Json<SpentCredentialsResponse>> {
|
||||
AxumResult::Err(AxumErrorResponse::internal_msg("permanently restricted"))
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ use nym_validator_client::EcashApiClient;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Client {
|
||||
async fn address(&self) -> AccountId;
|
||||
async fn address(&self) -> Result<AccountId>;
|
||||
|
||||
async fn dkg_contract_address(&self) -> Result<AccountId>;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ impl DkgClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_address(&self) -> AccountId {
|
||||
pub(crate) async fn get_address(&self) -> Result<AccountId, EcashError> {
|
||||
self.inner.address().await
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl DkgClient {
|
||||
|
||||
pub(crate) async fn group_member(&self) -> Result<MemberResponse, EcashError> {
|
||||
self.inner
|
||||
.group_member(self.get_address().await.to_string())
|
||||
.group_member(self.get_address().await?.to_string())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ impl DkgClient {
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Option<ContractVKShare>, EcashError> {
|
||||
let address = self.inner.address().await;
|
||||
let address = self.inner.address().await?;
|
||||
self.get_verification_key_share(epoch_id, address).await
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ impl DkgClient {
|
||||
}
|
||||
|
||||
pub(crate) async fn get_vote(&self, proposal_id: u64) -> Result<VoteResponse, EcashError> {
|
||||
let address = self.get_address().await.to_string();
|
||||
let address = self.get_address().await?.to_string();
|
||||
self.inner.get_vote(proposal_id, address).await
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
|
||||
resharing: bool,
|
||||
) -> Result<(), DealingGenerationError> {
|
||||
let dealing_state = self.state.dealing_exchange_state(epoch_id)?;
|
||||
let address = self.dkg_client.get_address().await.to_string();
|
||||
let address = self.dkg_client.get_address().await?.to_string();
|
||||
|
||||
let status = self
|
||||
.dkg_client
|
||||
@@ -259,7 +259,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
|
||||
.checked_sub(1)
|
||||
.expect("resharing epoch invariant has been broken");
|
||||
|
||||
let address = self.dkg_client.get_address().await;
|
||||
let address = self.dkg_client.get_address().await?;
|
||||
Ok(self
|
||||
.dkg_client
|
||||
.dealer_in_epoch(previous_epoch_id, address.to_string())
|
||||
|
||||
@@ -494,7 +494,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
|
||||
// submitted proposals and find the one with our address
|
||||
self.get_validation_proposals()
|
||||
.await?
|
||||
.get(self.dkg_client.get_address().await.as_ref())
|
||||
.get(self.dkg_client.get_address().await?.as_ref())
|
||||
.copied()
|
||||
.ok_or(KeyDerivationError::UnrecoverableProposalId)
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
|
||||
};
|
||||
|
||||
// if this is our share, obviously vote for yes without spending time on verification
|
||||
if owner.as_ref() == self.dkg_client.get_address().await.as_ref() {
|
||||
if owner.as_ref() == self.dkg_client.get_address().await?.as_ref() {
|
||||
votes.insert(*proposal_id, true);
|
||||
continue;
|
||||
}
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
exchange_dealings(&mut controllers, false).await;
|
||||
derive_keypairs(&mut controllers, false).await;
|
||||
|
||||
let first_dealer = controllers[0].dkg_client.get_address().await;
|
||||
let first_dealer = controllers[0].dkg_client.get_address().await?;
|
||||
|
||||
{
|
||||
let mut guard = chain.lock().unwrap();
|
||||
@@ -365,8 +365,8 @@ mod tests {
|
||||
exchange_dealings(&mut controllers, false).await;
|
||||
derive_keypairs(&mut controllers, false).await;
|
||||
|
||||
let first_dealer = controllers[0].dkg_client.get_address().await;
|
||||
let second_dealer = controllers[1].dkg_client.get_address().await;
|
||||
let first_dealer = controllers[0].dkg_client.get_address().await?;
|
||||
let second_dealer = controllers[1].dkg_client.get_address().await?;
|
||||
|
||||
{
|
||||
let mut guard = chain.lock().unwrap();
|
||||
|
||||
@@ -25,6 +25,9 @@ pub enum EcashError {
|
||||
#[error(transparent)]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[error("this instance is running without on-chain signing capabilities so no transactions can be sent")]
|
||||
ChainSignerNotEnabled,
|
||||
|
||||
#[error("this operation couldn't be completed as this nym-api is not an active ecash signer")]
|
||||
NotASigner,
|
||||
|
||||
|
||||
@@ -139,7 +139,9 @@ impl EcashState {
|
||||
.local
|
||||
.active_signer
|
||||
.get_or_init(epoch_id, || async {
|
||||
let address = self.aux.client.address().await;
|
||||
let Ok(address) = self.aux.client.address().await else {
|
||||
return Ok(false);
|
||||
};
|
||||
let ecash_signers = self.aux.comm_channel.ecash_clients(epoch_id).await?;
|
||||
|
||||
// check if any ecash signers for this epoch has the same cosmos address as this api
|
||||
@@ -246,7 +248,7 @@ impl EcashState {
|
||||
let threshold = self.aux.comm_channel.ecash_threshold(epoch_id).await?;
|
||||
|
||||
// let mut shares = Mutex::new(Vec::with_capacity(all_apis.len()));
|
||||
let cosmos_address = self.aux.client.address().await;
|
||||
let cosmos_address = self.aux.client.address().await.ok();
|
||||
|
||||
let get_partial_signatures = |api: EcashApiClient| async {
|
||||
// move the api into the closure
|
||||
@@ -256,7 +258,7 @@ impl EcashState {
|
||||
|
||||
// check if we're attempting to query ourselves, in that case just get local signature
|
||||
// rather than making the http query
|
||||
let partial = if api.cosmos_address == cosmos_address {
|
||||
let partial = if Some(api.cosmos_address) == cosmos_address {
|
||||
self.partial_coin_index_signatures(Some(epoch_id))
|
||||
.await?
|
||||
.signatures
|
||||
@@ -380,7 +382,7 @@ impl EcashState {
|
||||
let all_apis = self.aux.comm_channel.ecash_clients(epoch_id).await?;
|
||||
let threshold = self.aux.comm_channel.ecash_threshold(epoch_id).await?;
|
||||
|
||||
let cosmos_address = self.aux.client.address().await;
|
||||
let cosmos_address = self.aux.client.address().await.ok();
|
||||
|
||||
let get_partial_signatures = |api: EcashApiClient| async {
|
||||
// move the api into the closure
|
||||
@@ -390,7 +392,7 @@ impl EcashState {
|
||||
|
||||
// check if we're attempting to query ourselves, in that case just get local signature
|
||||
// rather than making the http query
|
||||
let partial = if api.cosmos_address == cosmos_address {
|
||||
let partial = if Some(api.cosmos_address) == cosmos_address {
|
||||
self.partial_expiration_date_signatures(expiration_date)
|
||||
.await?
|
||||
.signatures
|
||||
|
||||
@@ -263,7 +263,7 @@ pub(crate) struct TestingDkgController {
|
||||
|
||||
impl TestingDkgController {
|
||||
pub async fn address(&self) -> AccountId {
|
||||
self.dkg_client.get_address().await
|
||||
self.dkg_client.get_address().await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn cw_address(&self) -> Addr {
|
||||
|
||||
@@ -51,7 +51,7 @@ pub(crate) async fn initialise_dkg(controllers: &mut [TestingDkgController], res
|
||||
|
||||
// add every dealer to group contract
|
||||
for controller in controllers.iter() {
|
||||
let address = controller.dkg_client.get_address().await;
|
||||
let address = controller.dkg_client.get_address().await.unwrap();
|
||||
let mut chain = controllers[0].chain_state.lock().unwrap();
|
||||
chain.add_member(address.as_ref(), 10);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::node_describe_cache::DescribedNodes;
|
||||
use crate::node_status_api::handlers::unstable;
|
||||
use crate::node_status_api::NodeStatusCache;
|
||||
use crate::nym_contract_cache::cache::NymContractCache;
|
||||
use crate::status::ApiStatusState;
|
||||
use crate::support::caching::cache::SharedCache;
|
||||
use crate::support::config;
|
||||
use crate::support::http::state::{AppState, ForcedRefresh};
|
||||
@@ -524,8 +525,8 @@ impl DummyClient {
|
||||
|
||||
#[async_trait]
|
||||
impl super::client::Client for DummyClient {
|
||||
async fn address(&self) -> AccountId {
|
||||
self.validator_address.clone()
|
||||
async fn address(&self) -> Result<AccountId> {
|
||||
Ok(self.validator_address.clone())
|
||||
}
|
||||
|
||||
async fn dkg_contract_address(&self) -> Result<AccountId> {
|
||||
@@ -1262,7 +1263,7 @@ struct TestFixture {
|
||||
}
|
||||
|
||||
impl TestFixture {
|
||||
fn build_app_state(storage: NymApiStorage) -> AppState {
|
||||
fn build_app_state(storage: NymApiStorage, ecash_state: EcashState) -> AppState {
|
||||
AppState {
|
||||
forced_refresh: ForcedRefresh::new(true),
|
||||
nym_contract_cache: NymContractCache::new(),
|
||||
@@ -1275,6 +1276,8 @@ impl TestFixture {
|
||||
NymNetworkDetails::new_empty(),
|
||||
),
|
||||
node_info_cache: unstable::NodeInfoCache::default(),
|
||||
api_status: ApiStatusState::new(None),
|
||||
ecash_state: Arc::new(ecash_state),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,8 +1340,8 @@ impl TestFixture {
|
||||
TestFixture {
|
||||
axum: TestServer::new(
|
||||
Router::new()
|
||||
.nest("/v1/ecash", ecash_routes(Arc::new(ecash_state)))
|
||||
.with_state(Self::build_app_state(storage.clone())),
|
||||
.nest("/v1/ecash", ecash_routes())
|
||||
.with_state(Self::build_app_state(storage.clone(), ecash_state)),
|
||||
)
|
||||
.unwrap(),
|
||||
storage,
|
||||
|
||||
@@ -11,6 +11,9 @@ use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RewardingError {
|
||||
#[error("this instance is running without on-chain signing capabilities so no transactions can be sent")]
|
||||
ChainSignerNotEnabled,
|
||||
|
||||
#[error("Our account ({our_address}) is not permitted to update rewarded set and perform rewarding. The allowed address is {allowed_address}")]
|
||||
Unauthorised {
|
||||
our_address: AccountId,
|
||||
|
||||
@@ -134,9 +134,12 @@ impl EpochAdvancer {
|
||||
|
||||
let epoch_status = self.nyxd_client.get_current_epoch_status().await?;
|
||||
if !epoch_status.is_in_progress() {
|
||||
if epoch_status.being_advanced_by.as_str()
|
||||
!= self.nyxd_client.client_address().await.as_ref()
|
||||
{
|
||||
// SAFETY: before `EpochAdvancer` is started, `ensure_rewarding_permission` is called
|
||||
// which is not allowed to progress if this instance is not using a signing client
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let address = self.nyxd_client.client_address().await.unwrap();
|
||||
|
||||
if epoch_status.being_advanced_by.as_str() != address.as_ref() {
|
||||
// another nym-api is already handling
|
||||
error!("another nym-api ({}) is already advancing the epoch... but we shouldn't have other nym-apis yet!", epoch_status.being_advanced_by);
|
||||
return Ok(());
|
||||
@@ -318,8 +321,10 @@ impl EpochAdvancer {
|
||||
pub(crate) async fn ensure_rewarding_permission(
|
||||
nyxd_client: &Client,
|
||||
) -> Result<(), RewardingError> {
|
||||
let Some(our_address) = nyxd_client.client_address().await else {
|
||||
return Err(RewardingError::ChainSignerNotEnabled);
|
||||
};
|
||||
let allowed_address = nyxd_client.get_rewarding_validator_address().await?;
|
||||
let our_address = nyxd_client.client_address().await;
|
||||
if allowed_address != our_address {
|
||||
Err(RewardingError::Unauthorised {
|
||||
our_address,
|
||||
|
||||
@@ -4,37 +4,20 @@
|
||||
use crate::node_status_api::models::{AxumErrorResponse, AxumResult};
|
||||
use crate::status::ApiStatusState;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use axum::Router;
|
||||
use nym_api_requests::models::{ApiHealthResponse, SignerInformationResponse};
|
||||
use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use nym_compact_ecash::Base58;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) fn api_status_routes() -> Router<AppState> {
|
||||
let api_status_state = Arc::new(ApiStatusState::new());
|
||||
|
||||
Router::new()
|
||||
.route(
|
||||
"/health",
|
||||
axum::routing::get({
|
||||
let state = Arc::clone(&api_status_state);
|
||||
|| health(state)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
"/build-information",
|
||||
axum::routing::get({
|
||||
let state = Arc::clone(&api_status_state);
|
||||
|| build_information(state)
|
||||
}),
|
||||
)
|
||||
.route("/health", axum::routing::get(health))
|
||||
.route("/build-information", axum::routing::get(build_information))
|
||||
.route(
|
||||
"/signer-information",
|
||||
axum::routing::get({
|
||||
let state = Arc::clone(&api_status_state);
|
||||
|| signer_information(state)
|
||||
}),
|
||||
axum::routing::get(signer_information),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,7 +29,7 @@ pub(crate) fn api_status_routes() -> Router<AppState> {
|
||||
(status = 200, body = ApiHealthResponse)
|
||||
)
|
||||
)]
|
||||
async fn health(state: Arc<ApiStatusState>) -> Json<ApiHealthResponse> {
|
||||
async fn health(State(state): State<ApiStatusState>) -> Json<ApiHealthResponse> {
|
||||
let uptime = state.startup_time.elapsed();
|
||||
let health = ApiHealthResponse::new_healthy(uptime);
|
||||
Json(health)
|
||||
@@ -60,7 +43,9 @@ async fn health(state: Arc<ApiStatusState>) -> Json<ApiHealthResponse> {
|
||||
(status = 200, body = BinaryBuildInformationOwned)
|
||||
)
|
||||
)]
|
||||
async fn build_information(state: Arc<ApiStatusState>) -> Json<BinaryBuildInformationOwned> {
|
||||
async fn build_information(
|
||||
State(state): State<ApiStatusState>,
|
||||
) -> Json<BinaryBuildInformationOwned> {
|
||||
Json(state.build_information.to_owned())
|
||||
}
|
||||
|
||||
@@ -73,7 +58,7 @@ async fn build_information(state: Arc<ApiStatusState>) -> Json<BinaryBuildInform
|
||||
)
|
||||
)]
|
||||
async fn signer_information(
|
||||
state: Arc<ApiStatusState>,
|
||||
State(state): State<ApiStatusState>,
|
||||
) -> AxumResult<Json<SignerInformationResponse>> {
|
||||
let signer_state = state.signer_information.as_ref().ok_or_else(|| {
|
||||
AxumErrorResponse::internal_msg("this api does not expose zk-nym signing functionalities")
|
||||
|
||||
@@ -4,12 +4,25 @@
|
||||
use crate::ecash;
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::build_information::BinaryBuildInformation;
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use tokio::time::Instant;
|
||||
|
||||
pub(crate) mod handlers;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ApiStatusState {
|
||||
inner: Arc<ApiStatusStateInner>,
|
||||
}
|
||||
|
||||
impl Deref for ApiStatusState {
|
||||
type Target = ApiStatusStateInner;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ApiStatusStateInner {
|
||||
startup_time: Instant,
|
||||
build_information: BinaryBuildInformation,
|
||||
signer_information: Option<SignerState>,
|
||||
@@ -27,15 +40,13 @@ pub(crate) struct SignerState {
|
||||
}
|
||||
|
||||
impl ApiStatusState {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(signer_information: Option<SignerState>) -> Self {
|
||||
ApiStatusState {
|
||||
startup_time: Instant::now(),
|
||||
build_information: bin_info!(),
|
||||
signer_information: None,
|
||||
inner: Arc::new(ApiStatusStateInner {
|
||||
startup_time: Instant::now(),
|
||||
build_information: bin_info!(),
|
||||
signer_information,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_zk_nym_signer(&mut self, signer_information: SignerState) {
|
||||
self.signer_information = Some(signer_information)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::circulating_supply_api::cache::CirculatingSupplyCache;
|
||||
use crate::ecash::api_routes::handlers::ecash_routes;
|
||||
use crate::ecash::client::Client;
|
||||
use crate::ecash::comm::QueryCommunicationChannel;
|
||||
use crate::ecash::dkg::controller::keys::{
|
||||
@@ -138,8 +137,6 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
||||
let described_nodes_cache = SharedCache::<DescribedNodes>::new();
|
||||
let node_info_cache = unstable::NodeInfoCache::default();
|
||||
|
||||
let mut status_state = ApiStatusState::new();
|
||||
|
||||
let ecash_contract = nyxd_client
|
||||
.get_ecash_contract_address()
|
||||
.await
|
||||
@@ -161,8 +158,8 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
||||
|
||||
// if ecash signer is enabled, there are additional constraints on the nym-api,
|
||||
// such as having sufficient token balance
|
||||
let router = if config.ecash_signer.enabled {
|
||||
let cosmos_address = nyxd_client.address().await;
|
||||
let signer_information = if config.ecash_signer.enabled {
|
||||
let cosmos_address = nyxd_client.address().await?;
|
||||
|
||||
// make sure we have some tokens to cover multisig fees
|
||||
let balance = nyxd_client.balance(&mix_denom).await?;
|
||||
@@ -177,16 +174,14 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
||||
.clone()
|
||||
.map(|u| u.to_string())
|
||||
.unwrap_or_default();
|
||||
status_state.add_zk_nym_signer(SignerState {
|
||||
Some(SignerState {
|
||||
cosmos_address: cosmos_address.to_string(),
|
||||
identity: encoded_identity,
|
||||
announce_address,
|
||||
ecash_keypair: ecash_keypair_wrapper.clone(),
|
||||
});
|
||||
|
||||
router.nest("/v1/ecash", ecash_routes(Arc::new(ecash_state)))
|
||||
})
|
||||
} else {
|
||||
router
|
||||
None
|
||||
};
|
||||
|
||||
let router = router.with_state(AppState {
|
||||
@@ -200,6 +195,8 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
||||
described_nodes_cache: described_nodes_cache.clone(),
|
||||
network_details,
|
||||
node_info_cache,
|
||||
api_status: ApiStatusState::new(signer_information),
|
||||
ecash_state: Arc::new(ecash_state),
|
||||
});
|
||||
|
||||
let task_manager = TaskManager::new(TASK_MANAGER_TIMEOUT_S);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::circulating_supply_api::handlers::circulating_supply_routes;
|
||||
use crate::ecash::api_routes::handlers::ecash_routes;
|
||||
use crate::network::handlers::nym_network_routes;
|
||||
use crate::node_status_api::handlers::node_status_routes;
|
||||
use crate::nym_contract_cache::handlers::nym_contract_cache_routes;
|
||||
@@ -62,6 +63,7 @@ impl RouterBuilder {
|
||||
.nest("/network", nym_network_routes())
|
||||
.nest("/api-status", status::handlers::api_status_routes())
|
||||
.nest("/nym-nodes", nym_node_routes())
|
||||
.nest("/ecash", ecash_routes())
|
||||
.nest("/unstable", unstable_routes()), // CORS layer needs to be "outside" of routes
|
||||
);
|
||||
|
||||
@@ -70,6 +72,7 @@ impl RouterBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn nest(self, path: &str, router: Router<AppState>) -> Self {
|
||||
Self {
|
||||
unfinished_router: self.unfinished_router.nest(path, router),
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::circulating_supply_api::cache::CirculatingSupplyCache;
|
||||
use crate::ecash::state::EcashState;
|
||||
use crate::network::models::NetworkDetails;
|
||||
use crate::node_describe_cache::DescribedNodes;
|
||||
use crate::node_status_api::handlers::unstable;
|
||||
use crate::node_status_api::models::AxumErrorResponse;
|
||||
use crate::node_status_api::NodeStatusCache;
|
||||
use crate::nym_contract_cache::cache::{CachedRewardedSet, NymContractCache};
|
||||
use crate::status::ApiStatusState;
|
||||
use crate::support::caching::cache::SharedCache;
|
||||
use crate::support::caching::Cache;
|
||||
use crate::support::storage;
|
||||
use axum::extract::FromRef;
|
||||
use nym_api_requests::models::{GatewayBondAnnotated, MixNodeBondAnnotated, NodeAnnotation};
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use nym_task::TaskManager;
|
||||
@@ -80,6 +83,21 @@ pub(crate) struct AppState {
|
||||
pub(crate) described_nodes_cache: SharedCache<DescribedNodes>,
|
||||
pub(crate) network_details: NetworkDetails,
|
||||
pub(crate) node_info_cache: unstable::NodeInfoCache,
|
||||
pub(crate) api_status: ApiStatusState,
|
||||
// todo: refactor it into inner: Arc<EcashStateInner>
|
||||
pub(crate) ecash_state: Arc<EcashState>,
|
||||
}
|
||||
|
||||
impl FromRef<AppState> for ApiStatusState {
|
||||
fn from_ref(app_state: &AppState) -> Self {
|
||||
app_state.api_status.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRef<AppState> for Arc<EcashState> {
|
||||
fn from_ref(app_state: &AppState) -> Self {
|
||||
app_state.ecash_state.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -77,16 +77,6 @@ macro_rules! nyxd_query {
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! nyxd_signing_shared {
|
||||
($self:expr, $($op:tt)*) => {{
|
||||
let guard = $self.inner.read().await;
|
||||
match &*guard {
|
||||
$crate::support::nyxd::ClientInner::Signing(client) => client.$($op)*,
|
||||
$crate::support::nyxd::ClientInner::Query(_) => panic!("attempted to use a signing method on a query client"),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! nyxd_signing {
|
||||
($self:expr, $($op:tt)*) => {{
|
||||
let guard = $self.inner.write().await;
|
||||
@@ -140,13 +130,19 @@ impl Client {
|
||||
self.inner.read().await
|
||||
}
|
||||
|
||||
pub(crate) async fn client_address(&self) -> AccountId {
|
||||
nyxd_signing_shared!(self, address())
|
||||
pub(crate) async fn client_address(&self) -> Option<AccountId> {
|
||||
let guard = self.inner.read().await;
|
||||
match &*guard {
|
||||
ClientInner::Signing(client) => Some(client.address()),
|
||||
ClientInner::Query(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn balance<S: Into<String>>(&self, denom: S) -> Result<Coin, NyxdError> {
|
||||
let address = self.client_address().await;
|
||||
let denom = denom.into();
|
||||
let Some(address) = self.client_address().await else {
|
||||
return Ok(Coin::new(0, denom));
|
||||
};
|
||||
let balance = nyxd_query!(self, get_balance(&address, denom.clone()).await?);
|
||||
|
||||
match balance {
|
||||
@@ -394,8 +390,10 @@ impl Client {
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ecash::client::Client for Client {
|
||||
async fn address(&self) -> AccountId {
|
||||
self.client_address().await
|
||||
async fn address(&self) -> Result<AccountId, EcashError> {
|
||||
self.client_address()
|
||||
.await
|
||||
.ok_or(EcashError::ChainSignerNotEnabled)
|
||||
}
|
||||
|
||||
async fn dkg_contract_address(&self) -> Result<AccountId, EcashError> {
|
||||
@@ -481,7 +479,7 @@ impl crate::ecash::client::Client for Client {
|
||||
async fn get_self_registered_dealer_details(
|
||||
&self,
|
||||
) -> crate::ecash::error::Result<DealerDetailsResponse> {
|
||||
let self_address = &self.address().await;
|
||||
let self_address = &self.address().await?;
|
||||
Ok(nyxd_query!(self, get_dealer_details(self_address).await?))
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-node"
|
||||
version = "1.1.11"
|
||||
version = "1.1.12"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
@@ -36,7 +36,7 @@ impl MixnodeConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct Verloc {
|
||||
/// Socket address this node will use for binding its verloc API.
|
||||
/// default: `0.0.0.0:1790`
|
||||
|
||||
@@ -11,6 +11,7 @@ use nym_pemstore::store_keypair;
|
||||
use old_configs::old_config_v2::*;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -756,15 +757,16 @@ fn initialise(config: &WireguardV2) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn try_upgrade_config_v1<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV1>,
|
||||
) -> Result<ConfigV2, NymNodeError> {
|
||||
tracing::debug!("Updating from 1.1.2");
|
||||
debug!("attempting to load v1 config...");
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
prev_config
|
||||
} else {
|
||||
ConfigV1::read_from_path(&path)?
|
||||
ConfigV1::read_from_path(&path).inspect_err(|err| debug!("failed: {err}"))?
|
||||
};
|
||||
let wireguard = WireguardV2 {
|
||||
enabled: old_cfg.wireguard.enabled,
|
||||
|
||||
@@ -16,6 +16,7 @@ use nym_sphinx_acknowledgements::AckKey;
|
||||
use old_configs::old_config_v3::*;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -786,15 +787,16 @@ pub async fn initialise(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn try_upgrade_config_v2<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV2>,
|
||||
) -> Result<ConfigV3, NymNodeError> {
|
||||
tracing::debug!("Updating from 1.1.3");
|
||||
debug!("attempting to load v2 config...");
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
prev_config
|
||||
} else {
|
||||
ConfigV2::read_from_path(&path)?
|
||||
ConfigV2::read_from_path(&path).inspect_err(|err| debug!("failed: {err}"))?
|
||||
};
|
||||
|
||||
let authenticator_paths = AuthenticatorPathsV3::new(
|
||||
|
||||
@@ -17,6 +17,7 @@ use old_configs::old_config_v4::*;
|
||||
use persistence::*;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -938,15 +939,16 @@ pub async fn initialise(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn try_upgrade_config_v3<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV3>,
|
||||
) -> Result<ConfigV4, NymNodeError> {
|
||||
tracing::debug!("Updating from 1.1.4");
|
||||
debug!("attempting to load v3 config...");
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
prev_config
|
||||
} else {
|
||||
ConfigV3::read_from_path(&path)?
|
||||
ConfigV3::read_from_path(&path).inspect_err(|err| debug!("failed: {err}"))?
|
||||
};
|
||||
|
||||
let exit_gateway_paths = ExitGatewayPaths::new(
|
||||
|
||||
@@ -20,6 +20,7 @@ use old_configs::old_config_v5::*;
|
||||
use persistence::*;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -203,7 +204,7 @@ pub struct MixnetV4 {
|
||||
/// If applicable, custom port announced in the self-described API that other clients and nodes
|
||||
/// will use.
|
||||
/// Useful when the node is behind a proxy.
|
||||
#[serde(deserialize_with = "de_maybe_port")]
|
||||
#[serde(deserialize_with = "de_maybe_port", default)]
|
||||
pub announce_port: Option<u16>,
|
||||
|
||||
/// Addresses to nym APIs from which the node gets the view of the network.
|
||||
@@ -385,7 +386,7 @@ pub struct VerlocV4 {
|
||||
/// default: `0.0.0.0:1790`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
#[serde(deserialize_with = "de_maybe_port")]
|
||||
#[serde(deserialize_with = "de_maybe_port", default)]
|
||||
pub announce_port: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
@@ -1060,15 +1061,16 @@ pub async fn initialise(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV4>,
|
||||
) -> Result<ConfigV5, NymNodeError> {
|
||||
tracing::debug!("Updating from 1.1.5");
|
||||
debug!("attempting to load v4 config...");
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
prev_config
|
||||
} else {
|
||||
ConfigV4::read_from_path(&path)?
|
||||
ConfigV4::read_from_path(&path).inspect_err(|err| debug!("failed: {err}"))?
|
||||
};
|
||||
|
||||
let exit_gateway_paths = ExitGatewayPaths::new(
|
||||
|
||||
@@ -25,6 +25,7 @@ use nym_sphinx_acknowledgements::AckKey;
|
||||
use persistence::*;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -208,7 +209,7 @@ pub struct MixnetV5 {
|
||||
/// If applicable, custom port announced in the self-described API that other clients and nodes
|
||||
/// will use.
|
||||
/// Useful when the node is behind a proxy.
|
||||
#[serde(deserialize_with = "de_maybe_port")]
|
||||
#[serde(deserialize_with = "de_maybe_port", default)]
|
||||
pub announce_port: Option<u16>,
|
||||
|
||||
/// Addresses to nym APIs from which the node gets the view of the network.
|
||||
@@ -390,7 +391,7 @@ pub struct VerlocV5 {
|
||||
/// default: `0.0.0.0:1790`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
#[serde(deserialize_with = "de_maybe_port")]
|
||||
#[serde(deserialize_with = "de_maybe_port", default)]
|
||||
pub announce_port: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
@@ -1069,15 +1070,16 @@ pub async fn initialise(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn try_upgrade_config_v5<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV5>,
|
||||
) -> Result<Config, NymNodeError> {
|
||||
tracing::debug!("Updating from 1.1.6");
|
||||
debug!("attempting to load v5 config...");
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
prev_config
|
||||
} else {
|
||||
ConfigV5::read_from_path(&path)?
|
||||
ConfigV5::read_from_path(&path).inspect_err(|err| debug!("failed: {err}"))?
|
||||
};
|
||||
|
||||
let (private_ipv4, private_ipv6) = match old_cfg.wireguard.private_ip {
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::config::old_configs::*;
|
||||
use crate::config::Config;
|
||||
use crate::error::NymNodeError;
|
||||
use std::path::Path;
|
||||
use tracing::debug;
|
||||
|
||||
// currently there are no upgrades
|
||||
async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
|
||||
@@ -24,7 +25,10 @@ async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
|
||||
pub async fn try_load_current_config<P: AsRef<Path>>(
|
||||
config_path: P,
|
||||
) -> Result<Config, NymNodeError> {
|
||||
if let Ok(cfg) = Config::read_from_toml_file(config_path.as_ref()) {
|
||||
if let Ok(cfg) = Config::read_from_toml_file(config_path.as_ref())
|
||||
.inspect_err(|err| debug!("didn't manage to load the current config: {err}"))
|
||||
{
|
||||
debug!("managed to load the current version of the config");
|
||||
return Ok(cfg);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-network-requester"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version = "1.70"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-cli"
|
||||
version = "1.1.44"
|
||||
version = "1.1.45"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nymvisor"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
Reference in New Issue
Block a user