Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d09389c18 | |||
| eb07ec8580 | |||
| f6a79ce7c3 | |||
| 4ece8b7e8f | |||
| bb557985c0 | |||
| 3ebb24b2c8 | |||
| 97b01db23e |
+5
-13
@@ -4,21 +4,13 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.4] (2022-12-20)
|
||||
|
||||
This release adds multiple Single Use Reply Blocks (SURBs) to allow arbitrarily-sized anonymized replies.
|
||||
At the moment this is turned off by default, but available for use by application developers.
|
||||
We will need to wait for network-requesters to upgrade to this new release, after which multi-SURB anonymization will become the default setting for the SOCKS proxy clients.
|
||||
|
||||
The release also include some additional work for distributed key generation in the Coconut signing authority nodes.
|
||||
|
||||
### Changed
|
||||
|
||||
- Feature/dkg contract threshold by @neacsu in https://github.com/nymtech/nym/pull/1885
|
||||
- Multi-surbs by @jstuczyn in https://github.com/nymtech/nym/pull/2667
|
||||
- Fix multi-surb backwards compatibility in pre 1.1.4 client config files by @jstuczyn in https://github.com/nymtech/nym/pull/2703
|
||||
- fix: ignore corrupted surb storage and instead create fresh one by @jstuczyn in https://github.com/nymtech/nym/pull/2711
|
||||
- socks5: rework waiting in inbound.rs by @octol in https://github.com/nymtech/nym/pull/1880
|
||||
- all-binaries: improved error logging ([#2686])
|
||||
- native client: bring shutdown logic up to the same level as socks5-client
|
||||
|
||||
[#2686]: https://github.com/nymtech/nym/pull/2686
|
||||
|
||||
|
||||
## [v1.1.3] (2022-12-13)
|
||||
|
||||
|
||||
Generated
+35
-29
@@ -586,7 +586,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "client-core"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"client-connections",
|
||||
@@ -967,9 +967,9 @@ dependencies = [
|
||||
"coconut-interface",
|
||||
"cosmrs",
|
||||
"crypto",
|
||||
"nym-api-requests",
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
]
|
||||
|
||||
@@ -1116,6 +1116,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"subtle-encoding",
|
||||
"thiserror",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
@@ -2934,6 +2935,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"task",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-util 0.7.3",
|
||||
"url",
|
||||
@@ -3089,6 +3091,21 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"coconut-interface",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"getset",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-bity-integration"
|
||||
version = "0.1.0"
|
||||
@@ -3106,7 +3123,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@@ -3160,7 +3177,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"clap 3.2.8",
|
||||
"client-connections",
|
||||
@@ -3199,7 +3216,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3223,6 +3240,7 @@ dependencies = [
|
||||
"mixnet-client",
|
||||
"mixnode-common",
|
||||
"network-defaults",
|
||||
"nym-api-requests",
|
||||
"nymsphinx",
|
||||
"once_cell",
|
||||
"pemstore",
|
||||
@@ -3238,7 +3256,6 @@ dependencies = [
|
||||
"tokio-tungstenite 0.14.0",
|
||||
"tokio-util 0.7.3",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
"vergen 5.1.17",
|
||||
"version-checker",
|
||||
@@ -3246,7 +3263,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58",
|
||||
@@ -3288,7 +3305,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"clap 3.2.8",
|
||||
@@ -3320,7 +3337,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-statistics"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"log",
|
||||
@@ -3336,7 +3353,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"clap 3.2.8",
|
||||
"client-connections",
|
||||
@@ -3403,7 +3420,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-validator-api"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3434,6 +3451,7 @@ dependencies = [
|
||||
"logging",
|
||||
"mixnet-contract-common",
|
||||
"multisig-contract-common",
|
||||
"nym-api-requests",
|
||||
"nymcoconut",
|
||||
"nymsphinx",
|
||||
"okapi",
|
||||
@@ -3459,7 +3477,6 @@ dependencies = [
|
||||
"topology",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
"vergen 7.2.1",
|
||||
"version-checker",
|
||||
@@ -3541,6 +3558,7 @@ dependencies = [
|
||||
"nymsphinx-types",
|
||||
"pemstore",
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"topology",
|
||||
]
|
||||
|
||||
@@ -3615,6 +3633,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"nymsphinx-params",
|
||||
"nymsphinx-types",
|
||||
"thiserror",
|
||||
"tokio-util 0.7.3",
|
||||
]
|
||||
|
||||
@@ -3624,6 +3643,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"crypto",
|
||||
"nymsphinx-types",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3707,6 +3727,7 @@ name = "ordered-buffer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6189,10 +6210,10 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"mixnet-contract-common",
|
||||
"nym-api-requests",
|
||||
"nym-types",
|
||||
"nym-wallet-types",
|
||||
"ts-rs",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
"vesting-contract-common",
|
||||
"walkdir",
|
||||
@@ -6398,21 +6419,6 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
|
||||
[[package]]
|
||||
name = "validator-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"coconut-interface",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"getset",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator-client"
|
||||
version = "0.1.0"
|
||||
@@ -6437,6 +6443,7 @@ dependencies = [
|
||||
"mixnet-contract-common",
|
||||
"multisig-contract-common",
|
||||
"network-defaults",
|
||||
"nym-api-requests",
|
||||
"prost 0.10.3",
|
||||
"reqwest",
|
||||
"serde",
|
||||
@@ -6446,7 +6453,6 @@ dependencies = [
|
||||
"tokio",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"vesting-contract",
|
||||
"vesting-contract-common",
|
||||
]
|
||||
|
||||
+3
-3
@@ -74,8 +74,8 @@ members = [
|
||||
"mixnode",
|
||||
"service-providers/network-requester",
|
||||
"service-providers/network-statistics",
|
||||
"validator-api",
|
||||
"validator-api/validator-api-requests",
|
||||
"nym-api",
|
||||
"nym-api/nym-api-requests",
|
||||
"tools/nym-cli",
|
||||
"tools/ts-rs-cli"
|
||||
]
|
||||
@@ -87,7 +87,7 @@ default-members = [
|
||||
"service-providers/network-requester",
|
||||
"service-providers/network-statistics",
|
||||
"mixnode",
|
||||
"validator-api",
|
||||
"nym-api",
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client-core"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -36,19 +36,19 @@ use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tap::TapFallible;
|
||||
use task::{ShutdownListener, ShutdownNotifier};
|
||||
use task::{TaskClient, TaskManager};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
pub mod non_wasm_helpers;
|
||||
|
||||
pub struct ClientInput {
|
||||
pub shared_lane_queue_lengths: LaneQueueLengths,
|
||||
pub connection_command_sender: ConnectionCommandSender,
|
||||
pub input_sender: InputMessageSender,
|
||||
}
|
||||
|
||||
pub struct ClientOutput {
|
||||
pub shared_lane_queue_lengths: LaneQueueLengths,
|
||||
pub received_buffer_request_sender: ReceivedBufferRequestSender,
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ pub struct BaseClientBuilder<'a, B> {
|
||||
gateway_config: &'a GatewayEndpointConfig,
|
||||
debug_config: &'a DebugConfig,
|
||||
disabled_credentials: bool,
|
||||
validator_api_endpoints: Vec<Url>,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
reply_storage_backend: B,
|
||||
|
||||
bandwidth_controller: Option<BandwidthController>,
|
||||
@@ -106,7 +106,7 @@ where
|
||||
gateway_config: base_config.get_gateway_endpoint_config(),
|
||||
debug_config: base_config.get_debug_config(),
|
||||
disabled_credentials: base_config.get_disabled_credentials_mode(),
|
||||
validator_api_endpoints: base_config.get_validator_api_endpoints(),
|
||||
nym_api_endpoints: base_config.get_nym_api_endpoints(),
|
||||
bandwidth_controller,
|
||||
reply_storage_backend,
|
||||
key_manager,
|
||||
@@ -120,15 +120,15 @@ where
|
||||
bandwidth_controller: Option<BandwidthController>,
|
||||
reply_storage_backend: B,
|
||||
disabled_credentials: bool,
|
||||
validator_api_endpoints: Vec<Url>,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
) -> BaseClientBuilder<'a, B> {
|
||||
BaseClientBuilder {
|
||||
gateway_config,
|
||||
debug_config,
|
||||
disabled_credentials,
|
||||
validator_api_endpoints,
|
||||
bandwidth_controller,
|
||||
nym_api_endpoints,
|
||||
reply_storage_backend,
|
||||
bandwidth_controller,
|
||||
key_manager,
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ where
|
||||
self_address: Recipient,
|
||||
topology_accessor: TopologyAccessor,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) {
|
||||
info!("Starting loop cover traffic stream...");
|
||||
|
||||
@@ -185,7 +185,7 @@ where
|
||||
reply_controller_receiver: ReplyControllerReceiver,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_connection_rx: ConnectionCommandReceiver,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) {
|
||||
info!("Starting real traffic stream...");
|
||||
|
||||
@@ -212,7 +212,7 @@ where
|
||||
mixnet_receiver: MixnetMessageReceiver,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) {
|
||||
info!("Starting received messages buffer controller...");
|
||||
ReceivedMessagesBufferController::new(
|
||||
@@ -229,7 +229,7 @@ where
|
||||
&mut self,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<GatewayClient, ClientCoreError<B>> {
|
||||
let gateway_id = self.gateway_config.gateway_id.clone();
|
||||
if gateway_id.is_empty() {
|
||||
@@ -281,13 +281,13 @@ where
|
||||
// future responsible for periodically polling directory server and updating
|
||||
// the current global view of topology
|
||||
async fn start_topology_refresher(
|
||||
validator_api_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
topology_accessor: TopologyAccessor,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<(), ClientCoreError<B>> {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
validator_api_urls,
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
);
|
||||
@@ -317,7 +317,7 @@ where
|
||||
// requests?
|
||||
fn start_mix_traffic_controller(
|
||||
gateway_client: GatewayClient,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> BatchMixMessageSender {
|
||||
info!("Starting mix traffic controller...");
|
||||
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_client);
|
||||
@@ -327,7 +327,7 @@ where
|
||||
|
||||
async fn setup_persistent_reply_storage(
|
||||
backend: B,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<CombinedReplyStorage, ClientCoreError<B>> {
|
||||
let persistent_storage = PersistentReplyStorage::new(backend);
|
||||
let mem_store = persistent_storage
|
||||
@@ -367,7 +367,7 @@ where
|
||||
let shared_topology_accessor = TopologyAccessor::new();
|
||||
|
||||
// Shutdown notifier for signalling tasks to stop
|
||||
let shutdown = ShutdownNotifier::default();
|
||||
let task_manager = TaskManager::default();
|
||||
|
||||
// channels responsible for dealing with reply-related fun
|
||||
let (reply_controller_sender, reply_controller_receiver) =
|
||||
@@ -378,18 +378,20 @@ where
|
||||
// the components are started in very specific order. Unless you know what you are doing,
|
||||
// do not change that.
|
||||
let gateway_client = self
|
||||
.start_gateway_client(mixnet_messages_sender, ack_sender, shutdown.subscribe())
|
||||
.start_gateway_client(mixnet_messages_sender, ack_sender, task_manager.subscribe())
|
||||
.await?;
|
||||
|
||||
let reply_storage =
|
||||
Self::setup_persistent_reply_storage(self.reply_storage_backend, shutdown.subscribe())
|
||||
.await?;
|
||||
let reply_storage = Self::setup_persistent_reply_storage(
|
||||
self.reply_storage_backend,
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Self::start_topology_refresher(
|
||||
self.validator_api_endpoints.clone(),
|
||||
self.nym_api_endpoints.clone(),
|
||||
self.debug_config.topology_refresh_rate,
|
||||
shared_topology_accessor.clone(),
|
||||
shutdown.subscribe(),
|
||||
task_manager.subscribe(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -399,7 +401,7 @@ where
|
||||
mixnet_messages_receiver,
|
||||
reply_storage.key_storage(),
|
||||
reply_controller_sender.clone(),
|
||||
shutdown.subscribe(),
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
// The sphinx_message_sender is the transmitter for any component generating sphinx packets
|
||||
@@ -407,7 +409,7 @@ where
|
||||
// traffic stream.
|
||||
// The MixTrafficController then sends the actual traffic
|
||||
let sphinx_message_sender =
|
||||
Self::start_mix_traffic_controller(gateway_client, shutdown.subscribe());
|
||||
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
|
||||
|
||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||
// controller that connections are closed.
|
||||
@@ -439,7 +441,7 @@ where
|
||||
reply_controller_receiver,
|
||||
shared_lane_queue_lengths.clone(),
|
||||
client_connection_rx,
|
||||
shutdown.subscribe(),
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
if !self.debug_config.disable_loop_cover_traffic_stream {
|
||||
@@ -449,7 +451,7 @@ where
|
||||
self_address,
|
||||
shared_topology_accessor,
|
||||
sphinx_message_sender,
|
||||
shutdown.subscribe(),
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -459,17 +461,17 @@ where
|
||||
Ok(BaseClient {
|
||||
client_input: ClientInputStatus::AwaitingProducer {
|
||||
client_input: ClientInput {
|
||||
shared_lane_queue_lengths,
|
||||
connection_command_sender: client_connection_tx,
|
||||
input_sender,
|
||||
},
|
||||
},
|
||||
client_output: ClientOutputStatus::AwaitingConsumer {
|
||||
client_output: ClientOutput {
|
||||
shared_lane_queue_lengths,
|
||||
received_buffer_request_sender,
|
||||
},
|
||||
},
|
||||
shutdown_notifier: shutdown,
|
||||
task_manager,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -478,5 +480,5 @@ pub struct BaseClient {
|
||||
pub client_input: ClientInputStatus,
|
||||
pub client_output: ClientOutputStatus,
|
||||
|
||||
pub shutdown_notifier: ShutdownNotifier,
|
||||
pub task_manager: TaskManager,
|
||||
}
|
||||
|
||||
@@ -8,57 +8,6 @@ use crate::config::DebugConfig;
|
||||
use crate::error::ClientCoreError;
|
||||
use log::{error, info};
|
||||
use std::path::Path;
|
||||
use std::{fs, io};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
db_path: P,
|
||||
debug_config: &DebugConfig,
|
||||
) -> Result<fs_backend::Backend, ClientCoreError<fs_backend::Backend>> {
|
||||
info!("creating fresh surb database");
|
||||
let mut storage_backend = match fs_backend::Backend::init(db_path).await {
|
||||
Ok(backend) => backend,
|
||||
Err(err) => {
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}");
|
||||
return Err(ClientCoreError::SurbStorageError { source: err });
|
||||
}
|
||||
};
|
||||
|
||||
// while I kinda hate that we're going to be creating `CombinedReplyStorage` twice,
|
||||
// it will only be happening on the very first run and in practice won't incur huge
|
||||
// costs since the storage is going to be empty
|
||||
let mem_store = CombinedReplyStorage::new(
|
||||
debug_config.minimum_reply_surb_storage_threshold,
|
||||
debug_config.maximum_reply_surb_storage_threshold,
|
||||
);
|
||||
storage_backend
|
||||
.init_fresh(&mem_store)
|
||||
.await
|
||||
.map_err(|err| ClientCoreError::SurbStorageError { source: err })?;
|
||||
|
||||
Ok(storage_backend)
|
||||
}
|
||||
|
||||
fn archive_corrupted_database<P: AsRef<Path>>(db_path: P) -> io::Result<()> {
|
||||
let db_path = db_path.as_ref();
|
||||
debug_assert!(db_path.exists());
|
||||
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
|
||||
let suffix = format!("_{now}.corrupted");
|
||||
|
||||
let new_extension =
|
||||
if let Some(existing_extension) = db_path.extension().and_then(|ext| ext.to_str()) {
|
||||
format!("{existing_extension}.{}", suffix)
|
||||
} else {
|
||||
suffix
|
||||
};
|
||||
|
||||
let mut renamed = db_path.to_owned();
|
||||
renamed.set_extension(new_extension);
|
||||
|
||||
fs::rename(db_path, renamed)
|
||||
}
|
||||
|
||||
pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
db_path: P,
|
||||
@@ -71,13 +20,32 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
match fs_backend::Backend::try_load(db_path).await {
|
||||
Ok(backend) => Ok(backend),
|
||||
Err(err) => {
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future");
|
||||
|
||||
archive_corrupted_database(db_path)?;
|
||||
setup_fresh_backend(db_path, debug_config).await
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}");
|
||||
Err(ClientCoreError::SurbStorageError { source: err })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setup_fresh_backend(db_path, debug_config).await
|
||||
info!("creating fresh surb database");
|
||||
let mut storage_backend = match fs_backend::Backend::init(db_path).await {
|
||||
Ok(backend) => backend,
|
||||
Err(err) => {
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}");
|
||||
return Err(ClientCoreError::SurbStorageError { source: err });
|
||||
}
|
||||
};
|
||||
|
||||
// while I kinda hate that we're going to be creating `CombinedReplyStorage` twice,
|
||||
// it will only be happening on the very first run and in practice won't incur huge
|
||||
// costs since the storage is going to be empty
|
||||
let mem_store = CombinedReplyStorage::new(
|
||||
debug_config.minimum_reply_surb_storage_threshold,
|
||||
debug_config.maximum_reply_surb_storage_threshold,
|
||||
);
|
||||
storage_backend
|
||||
.init_fresh(&mem_store)
|
||||
.await
|
||||
.map_err(|err| ClientCoreError::SurbStorageError { source: err })?;
|
||||
|
||||
Ok(storage_backend)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
|
||||
// we should set initial delay only when we actually start the stream
|
||||
let sampled =
|
||||
sample_poisson_duration(&mut self.rng, self.average_cover_message_sending_delay);
|
||||
|
||||
@@ -51,8 +51,8 @@ impl MixTrafficController {
|
||||
};
|
||||
|
||||
match result {
|
||||
Err(e) => {
|
||||
error!("Failed to send sphinx packet(s) to the gateway! - {:?}", e);
|
||||
Err(err) => {
|
||||
error!("Failed to send sphinx packet(s) to the gateway! - {err}");
|
||||
self.consecutive_gateway_failure_count += 1;
|
||||
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
|
||||
// todo: in the future this should initiate a 'graceful' shutdown or try
|
||||
@@ -67,11 +67,11 @@ impl MixTrafficController {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started MixTrafficController with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
loop {
|
||||
tokio::select! {
|
||||
mix_packets = self.mix_rx.recv() => match mix_packets {
|
||||
Some(mix_packets) => {
|
||||
@@ -82,8 +82,9 @@ impl MixTrafficController {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("MixTrafficController: Received shutdown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ impl AcknowledgementListener {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started AcknowledgementListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
@@ -77,7 +77,7 @@ impl AcknowledgementListener {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("AcknowledgementListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -249,7 +249,7 @@ impl ActionController {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started ActionController with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
@@ -270,7 +270,7 @@ impl ActionController {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("ActionController: Received shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -109,7 +109,7 @@ where
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started InputMessageListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
@@ -123,7 +123,7 @@ where
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("InputMessageListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn start_with_shutdown(self, shutdown: task::ShutdownListener) {
|
||||
pub(super) fn start_with_shutdown(self, shutdown: task::TaskClient) {
|
||||
let mut acknowledgement_listener = self.acknowledgement_listener;
|
||||
let mut input_message_listener = self.input_message_listener;
|
||||
let mut retransmission_request_listener = self.retransmission_request_listener;
|
||||
|
||||
+2
-2
@@ -137,7 +137,7 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started RetransmissionRequestListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
@@ -149,7 +149,7 @@ where
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("RetransmissionRequestListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ impl SentNotificationListener {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started SentNotificationListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
@@ -51,7 +51,7 @@ impl SentNotificationListener {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("SentNotificationListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ impl RealMessagesController<OsRng> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: task::ShutdownListener) {
|
||||
pub fn start_with_shutdown(self, shutdown: task::TaskClient) {
|
||||
let mut out_queue_control = self.out_queue_control;
|
||||
let ack_control = self.ack_control;
|
||||
let mut reply_control = self.reply_control;
|
||||
|
||||
@@ -264,7 +264,7 @@ where
|
||||
};
|
||||
|
||||
if let Err(err) = self.mix_tx.send(vec![next_message]).await {
|
||||
log::error!("Failed to send: {}", err);
|
||||
log::error!("Failed to send: {err}");
|
||||
}
|
||||
|
||||
// notify ack controller about sending our message only after we actually managed to push it
|
||||
@@ -384,7 +384,10 @@ where
|
||||
match Pin::new(&mut self.real_receiver).poll_recv(cx) {
|
||||
// in the case our real message channel stream was closed, we should also indicate we are closed
|
||||
// (and whoever is using the stream should panic)
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Ready(None) => {
|
||||
log::error!("real receiver ready(none)");
|
||||
Poll::Ready(None)
|
||||
}
|
||||
|
||||
Poll::Ready(Some((real_messages, conn_id))) => {
|
||||
log::trace!("handling real_messages: size: {}", real_messages.len());
|
||||
@@ -469,7 +472,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn log_status(&self, shutdown: &mut task::ShutdownListener) {
|
||||
fn log_status(&self, shutdown: &mut task::TaskClient) {
|
||||
use crate::error::ClientCoreStatusMessage;
|
||||
|
||||
let packets = self.transmission_buffer.total_size();
|
||||
@@ -514,7 +517,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started OutQueueControl with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -525,7 +528,7 @@ where
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("OutQueueControl: Received shutdown");
|
||||
}
|
||||
_ = status_timer.tick() => {
|
||||
|
||||
+2
@@ -77,10 +77,12 @@ impl SendingDelayController {
|
||||
self.current_multiplier
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) fn min_multiplier(&self) -> u32 {
|
||||
self.lower_bound
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) fn max_multiplier(&self) -> u32 {
|
||||
self.upper_bound
|
||||
}
|
||||
|
||||
@@ -399,21 +399,20 @@ impl RequestReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started RequestReceiver with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("RequestReceiver: Received shutdown");
|
||||
}
|
||||
request = self.query_receiver.next() => {
|
||||
match request {
|
||||
Some(message) => self.handle_message(message).await,
|
||||
None => {
|
||||
log::trace!("RequestReceiver: Stopping since channel closed");
|
||||
break;
|
||||
},
|
||||
if let Some(message) = request {
|
||||
self.handle_message(message).await
|
||||
} else {
|
||||
log::trace!("RequestReceiver: Stopping since channel closed");
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -439,20 +438,19 @@ impl FragmentedMessageReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started FragmentedMessageReceiver with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
new_messages = self.mixnet_packet_receiver.next() => match new_messages {
|
||||
Some(new_messages) => {
|
||||
new_messages = self.mixnet_packet_receiver.next() => {
|
||||
if let Some(new_messages) = new_messages {
|
||||
self.received_buffer.handle_new_received(new_messages).await;
|
||||
}
|
||||
None => {
|
||||
} else {
|
||||
log::trace!("FragmentedMessageReceiver: Stopping since channel closed");
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("FragmentedMessageReceiver: Received shutdown");
|
||||
}
|
||||
}
|
||||
@@ -490,7 +488,7 @@ impl ReceivedMessagesBufferController {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: task::ShutdownListener) {
|
||||
pub fn start_with_shutdown(self, shutdown: task::TaskClient) {
|
||||
let mut fragmented_message_receiver = self.fragmented_message_receiver;
|
||||
let mut request_receiver = self.request_receiver;
|
||||
|
||||
|
||||
@@ -891,7 +891,7 @@ where
|
||||
return gloo_timers::future::IntervalStream::new(polling_rate.as_millis() as u32);
|
||||
}
|
||||
|
||||
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
debug!("Started ReplyController with graceful shutdown support");
|
||||
|
||||
let polling_rate = Duration::from_secs(5);
|
||||
@@ -904,7 +904,7 @@ where
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("ReplyController: Received shutdown");
|
||||
},
|
||||
req = self.request_receiver.next() => match req {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use self::error::StorageError;
|
||||
use crate::client::replies::reply_storage::backend::fs_backend::manager::StorageManager;
|
||||
use crate::client::replies::reply_storage::backend::fs_backend::models::{
|
||||
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
|
||||
@@ -16,8 +17,6 @@ use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub use self::error::StorageError;
|
||||
|
||||
mod error;
|
||||
mod manager;
|
||||
mod models;
|
||||
@@ -67,12 +66,6 @@ impl Backend {
|
||||
return Err(StorageError::IncompleteDataFlush);
|
||||
}
|
||||
|
||||
let last_flush_timestamp = manager.get_previous_flush_timestamp().await?;
|
||||
if last_flush_timestamp == 0 {
|
||||
// either this client has been running since 1970 or the flush failed
|
||||
return Err(StorageError::IncompleteDataFlush);
|
||||
}
|
||||
|
||||
// the process has gone down without full graceful shutdown,
|
||||
// meaning the database doesn't contain valid data anymore
|
||||
// so we have to purge it
|
||||
@@ -82,12 +75,7 @@ impl Backend {
|
||||
manager.delete_all_reply_keys().await?;
|
||||
}
|
||||
|
||||
if let Err(err) = manager.get_reply_surb_storage_metadata().await {
|
||||
// we can't recover here, we HAVE TO initialise fresh (because we don't know correct starting metadata)
|
||||
error!("it seems the client has been shutdown gracefully - we're missing valid surb data dump. the existing database cannot be used");
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
let last_flush_timestamp = manager.get_previous_flush_timestamp().await?;
|
||||
let last_flush = match OffsetDateTime::from_unix_timestamp(last_flush_timestamp) {
|
||||
Ok(last_flush) => last_flush,
|
||||
Err(err) => {
|
||||
|
||||
@@ -37,7 +37,7 @@ where
|
||||
pub async fn flush_on_shutdown(
|
||||
mut self,
|
||||
mem_state: CombinedReplyStorage,
|
||||
mut shutdown: task::ShutdownListener,
|
||||
mut shutdown: task::TaskClient,
|
||||
) {
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
|
||||
@@ -136,19 +136,15 @@ impl Default for TopologyAccessor {
|
||||
}
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
validator_api_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(
|
||||
validator_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
client_version: String,
|
||||
) -> Self {
|
||||
pub fn new(nym_api_urls: Vec<Url>, refresh_rate: Duration, client_version: String) -> Self {
|
||||
TopologyRefresherConfig {
|
||||
validator_api_urls,
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
client_version,
|
||||
}
|
||||
@@ -159,7 +155,7 @@ pub struct TopologyRefresher {
|
||||
validator_client: validator_client::client::ApiClient,
|
||||
client_version: String,
|
||||
|
||||
validator_api_urls: Vec<Url>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
refresh_rate: Duration,
|
||||
|
||||
@@ -169,14 +165,12 @@ pub struct TopologyRefresher {
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||
cfg.validator_api_urls.shuffle(&mut thread_rng());
|
||||
cfg.nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
TopologyRefresher {
|
||||
validator_client: validator_client::client::ApiClient::new(
|
||||
cfg.validator_api_urls[0].clone(),
|
||||
),
|
||||
validator_client: validator_client::client::ApiClient::new(cfg.nym_api_urls[0].clone()),
|
||||
client_version: cfg.client_version,
|
||||
validator_api_urls: cfg.validator_api_urls,
|
||||
nym_api_urls: cfg.nym_api_urls,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
currently_used_api: 0,
|
||||
@@ -184,15 +178,15 @@ impl TopologyRefresher {
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_validator_api(&mut self) {
|
||||
if self.validator_api_urls.len() == 1 {
|
||||
warn!("There's only a single validator API available - it won't be possible to use a different one");
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.validator_api_urls.len();
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_validator_api(self.validator_api_urls[self.currently_used_api].clone())
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
@@ -288,7 +282,7 @@ impl TopologyRefresher {
|
||||
let new_topology = self.get_current_compatible_topology().await;
|
||||
|
||||
if new_topology.is_none() {
|
||||
self.use_next_validator_api();
|
||||
self.use_next_nym_api();
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.was_latest_valid {
|
||||
@@ -310,7 +304,7 @@ impl TopologyRefresher {
|
||||
self.topology_accessor.ensure_is_routable().await
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::ShutdownListener) {
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
|
||||
@@ -88,28 +88,16 @@ impl<T> Config<T> {
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
self.client.id = id.into();
|
||||
self.set_empty_fields_to_defaults();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_empty_fields_to_defaults(&mut self) -> bool
|
||||
where
|
||||
T: NymConfig,
|
||||
{
|
||||
let id = &self.client.id;
|
||||
let mut changes_made = false;
|
||||
let id = id.into();
|
||||
|
||||
// identity key setting
|
||||
if self.client.private_identity_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.private_identity_key_file =
|
||||
self::Client::<T>::default_private_identity_key_file(id);
|
||||
self::Client::<T>::default_private_identity_key_file(&id);
|
||||
}
|
||||
if self.client.public_identity_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.public_identity_key_file =
|
||||
self::Client::<T>::default_public_identity_key_file(id);
|
||||
self::Client::<T>::default_public_identity_key_file(&id);
|
||||
}
|
||||
|
||||
// encryption key setting
|
||||
@@ -119,9 +107,8 @@ impl<T> Config<T> {
|
||||
.as_os_str()
|
||||
.is_empty()
|
||||
{
|
||||
changes_made = true;
|
||||
self.client.private_encryption_key_file =
|
||||
self::Client::<T>::default_private_encryption_key_file(id);
|
||||
self::Client::<T>::default_private_encryption_key_file(&id);
|
||||
}
|
||||
if self
|
||||
.client
|
||||
@@ -129,35 +116,32 @@ impl<T> Config<T> {
|
||||
.as_os_str()
|
||||
.is_empty()
|
||||
{
|
||||
changes_made = true;
|
||||
self.client.public_encryption_key_file =
|
||||
self::Client::<T>::default_public_encryption_key_file(id);
|
||||
self::Client::<T>::default_public_encryption_key_file(&id);
|
||||
}
|
||||
|
||||
// shared gateway key setting
|
||||
if self.client.gateway_shared_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.gateway_shared_key_file =
|
||||
self::Client::<T>::default_gateway_shared_key_file(id);
|
||||
self::Client::<T>::default_gateway_shared_key_file(&id);
|
||||
}
|
||||
|
||||
// ack key setting
|
||||
if self.client.ack_key_file.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.ack_key_file = self::Client::<T>::default_ack_key_file(id);
|
||||
self.client.ack_key_file = self::Client::<T>::default_ack_key_file(&id);
|
||||
}
|
||||
|
||||
if self.client.reply_surb_database_path.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.reply_surb_database_path =
|
||||
self::Client::<T>::default_reply_surb_database_path(id);
|
||||
self::Client::<T>::default_reply_surb_database_path(&id);
|
||||
}
|
||||
|
||||
if self.client.database_path.as_os_str().is_empty() {
|
||||
changes_made = true;
|
||||
self.client.database_path = self::Client::<T>::default_database_path(id);
|
||||
self.client.database_path = self::Client::<T>::default_database_path(&id);
|
||||
}
|
||||
changes_made
|
||||
|
||||
self.client.id = id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_disabled_credentials(&mut self, disabled_credentials_mode: bool) {
|
||||
@@ -176,8 +160,8 @@ impl<T> Config<T> {
|
||||
self.client.validator_urls = validator_urls;
|
||||
}
|
||||
|
||||
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
|
||||
self.client.validator_api_urls = validator_api_urls;
|
||||
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
|
||||
self.client.nym_api_urls = nym_api_urls;
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
@@ -237,8 +221,8 @@ impl<T> Config<T> {
|
||||
self.client.validator_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
|
||||
self.client.validator_api_urls.clone()
|
||||
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
|
||||
self.client.nym_api_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_id(&self) -> String {
|
||||
@@ -425,7 +409,8 @@ pub struct Client<T> {
|
||||
validator_urls: Vec<Url>,
|
||||
|
||||
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls: Vec<Url>,
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
nym_api_urls: Vec<Url>,
|
||||
|
||||
/// Path to file containing private identity key.
|
||||
private_identity_key_file: PathBuf,
|
||||
@@ -454,10 +439,6 @@ pub struct Client<T> {
|
||||
database_path: PathBuf,
|
||||
|
||||
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
|
||||
// this was set to use #[serde(default)] for the purposes of compatibility for multi-surbs introduced in 1.1.4.
|
||||
// if you're reading this message and we have already introduced some breaking changes, feel free
|
||||
// to remove that attribute since at this point the client configs should have gotten regenerated
|
||||
#[serde(default)]
|
||||
reply_surb_database_path: PathBuf,
|
||||
|
||||
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
||||
@@ -476,7 +457,7 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
id: "".to_string(),
|
||||
disabled_credentials_mode: true,
|
||||
validator_urls: vec![],
|
||||
validator_api_urls: vec![],
|
||||
nym_api_urls: vec![],
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
private_encryption_key_file: Default::default(),
|
||||
|
||||
@@ -30,8 +30,8 @@ pub enum ClientCoreError<B: ReplyStorageBackend> {
|
||||
#[error("Failed to setup gateway")]
|
||||
FailedToSetupGateway,
|
||||
|
||||
#[error("List of validator apis is empty")]
|
||||
ListOfValidatorApisIsEmpty,
|
||||
#[error("List of nym apis is empty")]
|
||||
ListOfNymApisIsEmpty,
|
||||
|
||||
#[error("Could not load existing gateway configuration: {0}")]
|
||||
CouldNotLoadExistingGatewayConfiguration(std::io::Error),
|
||||
|
||||
@@ -24,12 +24,12 @@ pub(super) async fn query_gateway_details<B>(
|
||||
where
|
||||
B: ReplyStorageBackend,
|
||||
{
|
||||
let validator_api = validator_servers
|
||||
let nym_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.ok_or(ClientCoreError::ListOfValidatorApisIsEmpty)?;
|
||||
let validator_client = validator_client::client::ApiClient::new(validator_api.clone());
|
||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
||||
let validator_client = validator_client::client::ApiClient::new(nym_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
log::trace!("Fetching list of gateways from: {}", nym_api);
|
||||
let gateways = validator_client.get_cached_gateways().await?;
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
|
||||
@@ -96,7 +96,7 @@ where
|
||||
{
|
||||
println!("Configuring gateway");
|
||||
let gateway =
|
||||
query_gateway_details(config.get_validator_api_endpoints(), user_chosen_gateway_id).await?;
|
||||
query_gateway_details(config.get_nym_api_endpoints(), user_chosen_gateway_id).await?;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// Registering with gateway by setting up and writing shared keys to disk
|
||||
@@ -120,11 +120,8 @@ where
|
||||
T: NymConfig,
|
||||
{
|
||||
println!("Using gateway provided by user, keeping existing keys");
|
||||
let gateway = query_gateway_details(
|
||||
config.get_validator_api_endpoints(),
|
||||
Some(user_chosen_gateway_id),
|
||||
)
|
||||
.await?;
|
||||
let gateway =
|
||||
query_gateway_details(config.get_nym_api_endpoints(), Some(user_chosen_gateway_id)).await?;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
Ok(gateway.into())
|
||||
}
|
||||
@@ -209,8 +206,8 @@ pub fn output_to_json<T: Serialize>(init_results: &T, output_file: &str) {
|
||||
match std::fs::File::create(output_file) {
|
||||
Ok(file) => match serde_json::to_writer_pretty(file, init_results) {
|
||||
Ok(_) => println!("Saved: {}", output_file),
|
||||
Err(err) => eprintln!("Could not save {}: {}", output_file, err),
|
||||
Err(err) => eprintln!("Could not save {}: {err}", output_file),
|
||||
},
|
||||
Err(err) => eprintln!("Could not save {}: {}", output_file, err),
|
||||
Err(err) => eprintln!("Could not save {}: {err}", output_file),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -31,8 +31,8 @@ validator_urls = [
|
||||
]
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
{{#each client.validator_api_urls }}
|
||||
nym_api_urls = [
|
||||
{{#each client.nym_api_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::error::ClientError;
|
||||
use crate::websocket;
|
||||
@@ -18,7 +20,7 @@ use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use task::{wait_for_signal, ShutdownNotifier};
|
||||
use task::TaskManager;
|
||||
|
||||
pub(crate) mod config;
|
||||
|
||||
@@ -56,7 +58,7 @@ impl SocketClient {
|
||||
.expect("No nymd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_validator_api_endpoints()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
@@ -85,16 +87,19 @@ impl SocketClient {
|
||||
client_input: ClientInput,
|
||||
client_output: ClientOutput,
|
||||
self_address: Recipient,
|
||||
shutdown: task::TaskClient,
|
||||
) {
|
||||
info!("Starting websocket listener...");
|
||||
|
||||
let ClientInput {
|
||||
shared_lane_queue_lengths,
|
||||
connection_command_sender,
|
||||
input_sender,
|
||||
} = client_input;
|
||||
|
||||
let received_buffer_request_sender = client_output.received_buffer_request_sender;
|
||||
let ClientOutput {
|
||||
shared_lane_queue_lengths,
|
||||
received_buffer_request_sender,
|
||||
} = client_output;
|
||||
|
||||
let websocket_handler = websocket::Handler::new(
|
||||
input_sender,
|
||||
@@ -104,32 +109,26 @@ impl SocketClient {
|
||||
shared_lane_queue_lengths,
|
||||
);
|
||||
|
||||
websocket::Listener::new(config.get_listening_port()).start(websocket_handler);
|
||||
websocket::Listener::new(config.get_listening_port()).start(websocket_handler, shutdown);
|
||||
}
|
||||
|
||||
/// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent)
|
||||
pub async fn run_socket_forever(self) -> Result<(), ClientError> {
|
||||
pub async fn run_socket_forever(self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let mut shutdown = self.start_socket().await?;
|
||||
wait_for_signal().await;
|
||||
|
||||
println!(
|
||||
"Received signal - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
|
||||
);
|
||||
let res = task::wait_for_signal_and_error(&mut shutdown).await;
|
||||
|
||||
log::info!("Sending shutdown");
|
||||
shutdown.signal_shutdown().ok();
|
||||
|
||||
// Some of these components have shutdown signalling implemented as part of socks5 work,
|
||||
// but since it's not fully implemented (yet) for all the components of the native client,
|
||||
// we don't try to wait and instead just stop immediately.
|
||||
log::info!("Waiting for tasks to finish... (Press ctrl-c to force)");
|
||||
shutdown.wait_for_shutdown().await;
|
||||
|
||||
log::info!("Stopping nym-client");
|
||||
Ok(())
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn start_socket(self) -> Result<ShutdownNotifier, ClientError> {
|
||||
pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
|
||||
if !self.config.get_socket_type().is_websocket() {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
@@ -150,12 +149,18 @@ impl SocketClient {
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
|
||||
Self::start_websocket_listener(&self.config, client_input, client_output, self_address);
|
||||
Self::start_websocket_listener(
|
||||
&self.config,
|
||||
client_input,
|
||||
client_output,
|
||||
self_address,
|
||||
started_client.task_manager.subscribe(),
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
info!("The address of this client is: {}", self_address);
|
||||
|
||||
Ok(started_client.shutdown_notifier)
|
||||
Ok(started_client.task_manager)
|
||||
}
|
||||
|
||||
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
|
||||
@@ -192,7 +197,7 @@ impl SocketClient {
|
||||
Ok(DirectClient {
|
||||
client_input,
|
||||
reconstructed_receiver,
|
||||
_shutdown_notifier: started_client.shutdown_notifier,
|
||||
_shutdown_notifier: started_client.task_manager,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -202,7 +207,7 @@ pub struct DirectClient {
|
||||
reconstructed_receiver: ReconstructedMessagesReceiver,
|
||||
|
||||
// we need to keep reference to this guy otherwise things will start dropping
|
||||
_shutdown_notifier: ShutdownNotifier,
|
||||
_shutdown_notifier: TaskManager,
|
||||
}
|
||||
|
||||
impl DirectClient {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use crate::client::config::{Config, SocketType};
|
||||
use crate::error::ClientError;
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use completions::{fig_generate, ArgShell};
|
||||
@@ -86,7 +87,7 @@ pub(crate) struct OverrideConfig {
|
||||
enabled_credentials_mode: bool,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Cli) -> Result<(), ClientError> {
|
||||
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let bin_name = "nym-native-client";
|
||||
|
||||
match &args.command {
|
||||
@@ -114,13 +115,13 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
|
||||
if let Some(raw_validators) = args.api_validators {
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(config::parse_validators(&raw_validators));
|
||||
.set_custom_nym_apis(config::parse_validators(&raw_validators));
|
||||
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
|
||||
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
|
||||
.expect("api validator not set");
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(config::parse_validators(&raw_validators));
|
||||
.set_custom_nym_apis(config::parse_validators(&raw_validators));
|
||||
}
|
||||
|
||||
if args.disable_socket {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use crate::{
|
||||
client::{config::Config, SocketClient},
|
||||
commands::{override_config, OverrideConfig},
|
||||
@@ -89,27 +91,23 @@ fn version_check(cfg: &Config) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), ClientError> {
|
||||
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let id = &args.id;
|
||||
|
||||
let mut config = match Config::load_from_file(Some(id)) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
|
||||
return Err(ClientError::FailedToLoadConfig(id.to_string()));
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
|
||||
return Err(Box::new(ClientError::FailedToLoadConfig(id.to_string())));
|
||||
}
|
||||
};
|
||||
|
||||
let override_config_fields = OverrideConfig::from(args.clone());
|
||||
config = override_config(config, override_config_fields);
|
||||
|
||||
if config.get_base_mut().set_empty_fields_to_defaults() {
|
||||
warn!("some of the core config options were left unset. the default values are going to get used instead.");
|
||||
}
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return Err(ClientError::FailedLocalVersionCheck);
|
||||
return Err(Box::new(ClientError::FailedLocalVersionCheck));
|
||||
}
|
||||
|
||||
SocketClient::new(config).run_socket_forever().await
|
||||
|
||||
@@ -59,7 +59,7 @@ pub(crate) struct Upgrade {
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {:?}", err);
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
@@ -110,7 +110,7 @@ fn minor_0_12_upgrade(
|
||||
.set_custom_version(to_version.to_string().as_ref());
|
||||
|
||||
config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
eprintln!("failed to overwrite config file! - {err}");
|
||||
print_failed_upgrade(config_version, &to_version);
|
||||
process::exit(1);
|
||||
});
|
||||
@@ -146,7 +146,7 @@ pub(crate) fn execute(args: &Upgrade) {
|
||||
let id = &args.id;
|
||||
|
||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {:?}", err);
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{crate_version, Parser};
|
||||
use error::ClientError;
|
||||
use logging::setup_logging;
|
||||
use network_defaults::setup_env;
|
||||
|
||||
@@ -12,7 +13,7 @@ pub mod error;
|
||||
pub mod websocket;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), ClientError> {
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
setup_logging();
|
||||
println!("{}", banner());
|
||||
|
||||
|
||||
@@ -43,29 +43,16 @@ pub(crate) struct Handler {
|
||||
socket: Option<WebSocketStream<TcpStream>>,
|
||||
received_response_type: ReceivedResponseType,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
}
|
||||
|
||||
// clone is used to use handler on a new connection, which initially is `None`
|
||||
impl Clone for Handler {
|
||||
fn clone(&self) -> Self {
|
||||
Handler {
|
||||
msg_input: self.msg_input.clone(),
|
||||
client_connection_tx: self.client_connection_tx.clone(),
|
||||
buffer_requester: self.buffer_requester.clone(),
|
||||
self_full_address: self.self_full_address,
|
||||
socket: None,
|
||||
received_response_type: Default::default(),
|
||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||
}
|
||||
}
|
||||
is_active: bool,
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
fn drop(&mut self) {
|
||||
if self
|
||||
.buffer_requester
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverDisconnect)
|
||||
.is_err()
|
||||
if self.is_active
|
||||
&& self
|
||||
.buffer_requester
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverDisconnect)
|
||||
.is_err()
|
||||
{
|
||||
error!("we failed to disconnect the receiver from the buffer! presumably the shutdown procedure has been initiated!")
|
||||
}
|
||||
@@ -88,6 +75,22 @@ impl Handler {
|
||||
socket: None,
|
||||
received_response_type: Default::default(),
|
||||
lane_queue_lengths,
|
||||
is_active: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Used to use handler on a new connection, which initially is `None`
|
||||
// TODO: make sure we only ever have one active handler
|
||||
pub fn create_active_handler(&self) -> Self {
|
||||
Handler {
|
||||
msg_input: self.msg_input.clone(),
|
||||
client_connection_tx: self.client_connection_tx.clone(),
|
||||
buffer_requester: self.buffer_requester.clone(),
|
||||
self_full_address: self.self_full_address,
|
||||
socket: None,
|
||||
received_response_type: Default::default(),
|
||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||
is_active: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,8 +365,12 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async fn listen_for_requests(&mut self, mut msg_receiver: ReconstructedMessagesReceiver) {
|
||||
loop {
|
||||
async fn listen_for_requests(
|
||||
&mut self,
|
||||
mut msg_receiver: ReconstructedMessagesReceiver,
|
||||
mut task_client: task::TaskClient,
|
||||
) {
|
||||
while !task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
// we can either get a client request from the websocket
|
||||
socket_msg = self.next_websocket_request() => {
|
||||
@@ -373,7 +380,7 @@ impl Handler {
|
||||
let socket_msg = match socket_msg.unwrap() {
|
||||
Ok(socket_msg) => socket_msg,
|
||||
Err(err) => {
|
||||
warn!("failed to obtain message from websocket stream! stopping connection handler: {}", err);
|
||||
warn!("failed to obtain message from websocket stream! stopping connection handler: {err}");
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -397,21 +404,33 @@ impl Handler {
|
||||
error!("mix messages sender was unexpectedly closed! this shouldn't have ever happened! (unless we're shutting down - TODO: implement proper graceful shutdown handler)");
|
||||
return
|
||||
};
|
||||
if let Err(e) = self.push_websocket_received_plaintexts(mix_messages).await {
|
||||
warn!("failed to send sphinx packets back to the client - {:?}, assuming the connection is dead", e);
|
||||
if let Err(err) = self.push_websocket_received_plaintexts(mix_messages).await {
|
||||
warn!("failed to send sphinx packets back to the client - {err}, assuming the connection is dead");
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ = task_client.recv() => {
|
||||
log::trace!("Websocket handler: Received shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("Websocket handler: Exiting");
|
||||
}
|
||||
|
||||
// consume self to make sure `drop` is called after this is done
|
||||
pub(crate) async fn handle_connection(mut self, socket: TcpStream) {
|
||||
pub(crate) async fn handle_connection(
|
||||
mut self,
|
||||
socket: TcpStream,
|
||||
mut task_client: task::TaskClient,
|
||||
) {
|
||||
// We don't want a crash in the connection handler to trigger a shutdown of the whole
|
||||
// process.
|
||||
task_client.mark_as_success();
|
||||
|
||||
let ws_stream = match accept_async(socket).await {
|
||||
Ok(ws_stream) => ws_stream,
|
||||
Err(err) => {
|
||||
warn!("error while performing the websocket handshake - {:?}", err);
|
||||
warn!("error while performing the websocket handshake - {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -426,7 +445,8 @@ impl Handler {
|
||||
))
|
||||
.expect("the buffer request failed!");
|
||||
|
||||
self.listen_for_requests(reconstructed_receiver).await;
|
||||
self.listen_for_requests(reconstructed_receiver, task_client)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,11 +32,11 @@ impl Listener {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn run(&mut self, handler: Handler) {
|
||||
pub(crate) async fn run(&mut self, handler: Handler, mut task_client: task::TaskClient) {
|
||||
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
|
||||
Ok(listener) => listener,
|
||||
Err(err) => {
|
||||
error!("Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address, err);
|
||||
error!("Failed to bind to {} - {err}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
@@ -45,10 +45,23 @@ impl Listener {
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
// When the handler finishes we check if shutdown is signalled
|
||||
_ = notify.notified() => {
|
||||
if task_client.is_shutdown() {
|
||||
log::trace!("Websocket listener: detected shutdown after connection closed");
|
||||
break;
|
||||
}
|
||||
// our connection terminated - we are open to a new one now!
|
||||
self.state = State::AwaitingConnection;
|
||||
}
|
||||
// ... but when there is no connected client at the time of shutdown being
|
||||
// signalled, we handle it here.
|
||||
_ = task_client.recv() => {
|
||||
if !self.state.is_connected() {
|
||||
log::trace!("Not connected: shutting down");
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_conn = tcp_listener.accept() => {
|
||||
match new_conn {
|
||||
Ok((mut socket, remote_addr)) => {
|
||||
@@ -63,31 +76,33 @@ impl Listener {
|
||||
Ok(_) => trace!(
|
||||
"closed the connection between attempting websocket handshake"
|
||||
),
|
||||
Err(e) => warn!("failed to cleanly close the connection - {:?}", e),
|
||||
Err(err) => warn!("failed to cleanly close the connection - {err}"),
|
||||
};
|
||||
} else {
|
||||
// even though we're spawning a new task with the handler here, we will only ever spawn a single one.
|
||||
// it's done so that any new connections to this listener could be rejected rather than left
|
||||
// hanging because the executor doesn't come back here
|
||||
let notify_clone = Arc::clone(¬ify);
|
||||
let fresh_handler = handler.clone();
|
||||
let fresh_handler = handler.create_active_handler();
|
||||
let task_client_handler = task_client.clone();
|
||||
tokio::spawn(async move {
|
||||
fresh_handler.handle_connection(socket).await;
|
||||
fresh_handler.handle_connection(socket, task_client_handler).await;
|
||||
notify_clone.notify_one();
|
||||
});
|
||||
self.state = State::Connected;
|
||||
}
|
||||
}
|
||||
Err(e) => warn!("failed to get client: {:?}", e),
|
||||
Err(err) => warn!("failed to get client: {err}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("Websocket listener: Exiting");
|
||||
}
|
||||
|
||||
pub(crate) fn start(mut self, handler: Handler) -> JoinHandle<()> {
|
||||
pub(crate) fn start(mut self, handler: Handler, shutdown: task::TaskClient) -> JoinHandle<()> {
|
||||
info!("Running websocket on {:?}", self.address.to_string());
|
||||
|
||||
tokio::spawn(async move { self.run(handler).await })
|
||||
tokio::spawn(async move { self.run(handler, shutdown).await })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ impl ClientRequest {
|
||||
Err(err) => {
|
||||
return Err(error::Error::new(
|
||||
ErrorKind::MalformedRequest,
|
||||
format!("malformed recipient: {:?}", err),
|
||||
format!("malformed recipient: {err}"),
|
||||
))
|
||||
}
|
||||
};
|
||||
@@ -210,7 +210,7 @@ impl ClientRequest {
|
||||
Err(err) => {
|
||||
return Err(error::Error::new(
|
||||
ErrorKind::MalformedRequest,
|
||||
format!("malformed recipient: {:?}", err),
|
||||
format!("malformed recipient: {err}"),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -173,7 +173,7 @@ impl ServerResponse {
|
||||
Err(err) => {
|
||||
return Err(error::Error::new(
|
||||
ErrorKind::MalformedResponse,
|
||||
format!("malformed Recipient: {:?}", err),
|
||||
format!("malformed Recipient: {err}"),
|
||||
))
|
||||
}
|
||||
};
|
||||
@@ -249,7 +249,7 @@ impl ServerResponse {
|
||||
Err(err) => {
|
||||
return Err(error::Error::new(
|
||||
ErrorKind::MalformedResponse,
|
||||
format!("malformed error message: {:?}", err),
|
||||
format!("malformed error message: {err}"),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.4"
|
||||
version = "1.1.3"
|
||||
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"
|
||||
|
||||
@@ -143,7 +143,6 @@ pub struct Socks5 {
|
||||
/// slower and consume nearly double the bandwidth as it will require sending reply SURBs.
|
||||
///
|
||||
/// Note that some service providers might not support this.
|
||||
#[serde(default)]
|
||||
send_anonymously: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ validator_urls = [
|
||||
]
|
||||
|
||||
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||
validator_api_urls = [
|
||||
{{#each client.validator_api_urls }}
|
||||
nym_api_urls = [
|
||||
{{#each client.nym_api_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
@@ -19,7 +19,7 @@ use gateway_client::bandwidth::BandwidthController;
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use std::error::Error;
|
||||
use task::{wait_for_signal_and_error, ShutdownListener, ShutdownNotifier};
|
||||
use task::{wait_for_signal_and_error, TaskClient, TaskManager};
|
||||
|
||||
pub mod config;
|
||||
|
||||
@@ -67,7 +67,7 @@ impl NymClient {
|
||||
.expect("No nymd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_validator_api_endpoints()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
@@ -96,19 +96,21 @@ impl NymClient {
|
||||
client_input: ClientInput,
|
||||
client_output: ClientOutput,
|
||||
self_address: Recipient,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) {
|
||||
info!("Starting socks5 listener...");
|
||||
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||
let allowed_users: Vec<User> = Vec::new();
|
||||
|
||||
let ClientInput {
|
||||
shared_lane_queue_lengths,
|
||||
connection_command_sender,
|
||||
input_sender,
|
||||
} = client_input;
|
||||
|
||||
let received_buffer_request_sender = client_output.received_buffer_request_sender;
|
||||
let ClientOutput {
|
||||
shared_lane_queue_lengths,
|
||||
received_buffer_request_sender,
|
||||
} = client_output;
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
let mut sphinx_socks = SphinxSocksServer::new(
|
||||
@@ -200,7 +202,7 @@ impl NymClient {
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn start(self) -> Result<ShutdownNotifier, Socks5ClientError> {
|
||||
pub async fn start(self) -> Result<TaskManager, Socks5ClientError> {
|
||||
let base_builder = BaseClientBuilder::new_from_base_config(
|
||||
self.config.get_base(),
|
||||
self.key_manager,
|
||||
@@ -222,12 +224,12 @@ impl NymClient {
|
||||
client_input,
|
||||
client_output,
|
||||
self_address,
|
||||
started_client.shutdown_notifier.subscribe(),
|
||||
started_client.task_manager.subscribe(),
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
info!("The address of this client is: {}", self_address);
|
||||
|
||||
Ok(started_client.shutdown_notifier)
|
||||
Ok(started_client.task_manager)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,11 +116,11 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
|
||||
if let Some(raw_validators) = args.api_validators {
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||
.set_custom_nym_apis(parse_validators(&raw_validators));
|
||||
} else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) {
|
||||
config
|
||||
.get_base_mut()
|
||||
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||
.set_custom_nym_apis(parse_validators(&raw_validators));
|
||||
}
|
||||
|
||||
if args.use_anonymous_sender_tag {
|
||||
|
||||
@@ -43,9 +43,9 @@ pub(crate) struct Run {
|
||||
#[clap(long)]
|
||||
nymd_validators: Option<String>,
|
||||
|
||||
/// Comma separated list of rest endpoints of the API validators
|
||||
/// Comma separated list of rest endpoints of the Nym APIs
|
||||
#[clap(long)]
|
||||
api_validators: Option<String>,
|
||||
nym_apis: Option<String>,
|
||||
|
||||
/// Port for the socket to listen on
|
||||
#[clap(short, long)]
|
||||
@@ -71,7 +71,7 @@ impl From<Run> for OverrideConfig {
|
||||
fn from(run_config: Run) -> Self {
|
||||
OverrideConfig {
|
||||
nymd_validators: run_config.nymd_validators,
|
||||
api_validators: run_config.api_validators,
|
||||
api_validators: run_config.nym_apis,
|
||||
port: run_config.port,
|
||||
use_anonymous_sender_tag: run_config.use_anonymous_sender_tag,
|
||||
fastmode: run_config.fastmode,
|
||||
@@ -110,7 +110,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
|
||||
let mut config = match Config::load_from_file(Some(id)) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
|
||||
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
|
||||
return Err(Box::new(Socks5ClientError::FailedToLoadConfig(
|
||||
id.to_string(),
|
||||
)));
|
||||
@@ -120,10 +120,6 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
|
||||
let override_config_fields = OverrideConfig::from(args.clone());
|
||||
config = override_config(config, override_config_fields);
|
||||
|
||||
if config.get_base_mut().set_empty_fields_to_defaults() {
|
||||
warn!("some of the core config options were left unset. the default values are going to get used instead.");
|
||||
}
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck));
|
||||
|
||||
@@ -58,7 +58,7 @@ pub(crate) struct Upgrade {
|
||||
|
||||
fn parse_config_version(config: &Config) -> Version {
|
||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||
eprintln!("failed to parse client version! - {:?}", err);
|
||||
eprintln!("failed to parse client version! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
@@ -109,7 +109,7 @@ fn minor_0_12_upgrade(
|
||||
.set_custom_version(to_version.to_string().as_ref());
|
||||
|
||||
config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
eprintln!("failed to overwrite config file! - {err}");
|
||||
print_failed_upgrade(config_version, &to_version);
|
||||
process::exit(1);
|
||||
});
|
||||
@@ -145,7 +145,7 @@ pub(crate) fn execute(args: &Upgrade) {
|
||||
let id = &args.id;
|
||||
|
||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {:?}", err);
|
||||
eprintln!("failed to load existing config file! - {err}");
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ use socks5_requests::{ConnectionId, Message, RemoteAddress, Request};
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||
use tokio::{self, net::TcpStream};
|
||||
|
||||
@@ -164,7 +164,7 @@ pub(crate) struct SocksClient {
|
||||
self_address: Recipient,
|
||||
started_proxy: bool,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
shutdown_listener: ShutdownListener,
|
||||
shutdown_listener: TaskClient,
|
||||
}
|
||||
|
||||
impl Drop for SocksClient {
|
||||
@@ -190,7 +190,7 @@ impl SocksClient {
|
||||
controller_sender: ControllerSender,
|
||||
self_address: &Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
mut shutdown_listener: ShutdownListener,
|
||||
mut shutdown_listener: TaskClient,
|
||||
) -> Self {
|
||||
// If this task fails and exits, we don't want to send shutdown signal
|
||||
shutdown_listener.mark_as_success();
|
||||
@@ -220,7 +220,7 @@ impl SocksClient {
|
||||
}
|
||||
|
||||
pub async fn send_error(&mut self, err: SocksProxyError) -> Result<(), SocksProxyError> {
|
||||
let error_text = format!("{}", err);
|
||||
let error_text = format!("{err}");
|
||||
let Some(ref version) = self.socks_version else {
|
||||
log::error!("Trying to send error without knowing the version");
|
||||
return Ok(());
|
||||
|
||||
@@ -9,13 +9,13 @@ use client_core::client::received_buffer::{ReceivedBufferMessage, ReceivedBuffer
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
|
||||
use socks5_requests::Message;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
|
||||
pub(crate) struct MixnetResponseListener {
|
||||
buffer_requester: ReceivedBufferRequestSender,
|
||||
mix_response_receiver: ReconstructedMessagesReceiver,
|
||||
controller_sender: ControllerSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl Drop for MixnetResponseListener {
|
||||
@@ -25,9 +25,9 @@ impl Drop for MixnetResponseListener {
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverDisconnect)
|
||||
{
|
||||
if self.shutdown.is_shutdown_poll() {
|
||||
log::debug!("The buffer request failed: {}", err);
|
||||
log::debug!("The buffer request failed: {err}");
|
||||
} else {
|
||||
log::error!("The buffer request failed: {}", err);
|
||||
log::error!("The buffer request failed: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ impl MixnetResponseListener {
|
||||
pub(crate) fn new(
|
||||
buffer_requester: ReceivedBufferRequestSender,
|
||||
controller_sender: ControllerSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Self {
|
||||
let (mix_response_sender, mix_response_receiver) = mpsc::unbounded();
|
||||
buffer_requester
|
||||
@@ -60,7 +60,7 @@ impl MixnetResponseListener {
|
||||
|
||||
let response = match Message::try_from_bytes(&raw_message) {
|
||||
Err(err) => {
|
||||
warn!("failed to parse received response - {:?}", err);
|
||||
warn!("failed to parse received response - {err}");
|
||||
return;
|
||||
}
|
||||
Ok(Message::Request(_)) => {
|
||||
|
||||
@@ -13,7 +13,7 @@ use nymsphinx::addressing::clients::Recipient;
|
||||
use proxy_helpers::connection_controller::{BroadcastActiveConnections, Controller};
|
||||
use std::net::SocketAddr;
|
||||
use tap::TapFallible;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
/// A Socks5 server that listens for connections.
|
||||
@@ -24,7 +24,7 @@ pub struct SphinxSocksServer {
|
||||
self_address: Recipient,
|
||||
client_config: client::Config,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl SphinxSocksServer {
|
||||
@@ -36,7 +36,7 @@ impl SphinxSocksServer {
|
||||
self_address: Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_config: client::Config,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Self {
|
||||
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
||||
// just modify the config
|
||||
@@ -103,7 +103,7 @@ impl SphinxSocksServer {
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(err) = client.run().await {
|
||||
error!("Error! {}", err);
|
||||
error!("Error! {err}");
|
||||
if client.send_error(err).await.is_err() {
|
||||
warn!("Failed to send error code");
|
||||
};
|
||||
|
||||
@@ -40,7 +40,7 @@ pub enum SocksProxyError {
|
||||
impl std::fmt::Display for SocksProxyError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SocksProxyError::GenericError(err) => write!(f, "GenericError - {}", err),
|
||||
SocksProxyError::GenericError(err) => write!(f, "GenericError - {err}"),
|
||||
SocksProxyError::UnsupportedProxyVersion(version) => {
|
||||
write!(f, "Unsupported proxy version {}", version)
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ export default class ValidatorClient implements INymClient {
|
||||
static async connect(
|
||||
mnemonic: string,
|
||||
nymdUrl: string,
|
||||
validatorApiUrl: string,
|
||||
nymApiUrl: string,
|
||||
prefix: string,
|
||||
mixnetContract: string,
|
||||
vestingContract: string,
|
||||
@@ -94,19 +94,19 @@ export default class ValidatorClient implements INymClient {
|
||||
): Promise<ValidatorClient> {
|
||||
const wallet = await ValidatorClient.buildWallet(mnemonic, prefix);
|
||||
|
||||
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, validatorApiUrl, prefix, denom);
|
||||
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, nymApiUrl, prefix, denom);
|
||||
return new ValidatorClient(signingClient, prefix, mixnetContract, vestingContract, denom);
|
||||
}
|
||||
|
||||
static async connectForQuery(
|
||||
nymdUrl: string,
|
||||
validatorApiUrl: string,
|
||||
nymApiUrl: string,
|
||||
prefix: string,
|
||||
mixnetContract: string,
|
||||
vestingContract: string,
|
||||
denom: string,
|
||||
): Promise<ValidatorClient> {
|
||||
const queryClient = await QueryClient.connectWithNym(nymdUrl, validatorApiUrl);
|
||||
const queryClient = await QueryClient.connectWithNym(nymdUrl, nymApiUrl);
|
||||
return new ValidatorClient(queryClient, prefix, mixnetContract, vestingContract, denom);
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -6,13 +6,13 @@
|
||||
import axios from 'axios';
|
||||
import { GatewayBond, MixNodeBond } from './types';
|
||||
|
||||
export const VALIDATOR_API_VERSION = '/v1';
|
||||
export const VALIDATOR_API_GATEWAYS_PATH = `${VALIDATOR_API_VERSION}/gateways`;
|
||||
export const VALIDATOR_API_MIXNODES_PATH = `${VALIDATOR_API_VERSION}/mixnodes`;
|
||||
export const VALIDATOR_API_ACTIVE_MIXNODES_PATH = `${VALIDATOR_API_VERSION}/mixnodes/active`;
|
||||
export const VALIDATOR_API_REWARDED_MIXNODES_PATH = `${VALIDATOR_API_VERSION}/mixnodes/rewarded`;
|
||||
export const NYM_API_VERSION = '/v1';
|
||||
export const NYM_API_GATEWAYS_PATH = `${NYM_API_VERSION}/gateways`;
|
||||
export const NYM_API_MIXNODES_PATH = `${NYM_API_VERSION}/mixnodes`;
|
||||
export const NYM_API_ACTIVE_MIXNODES_PATH = `${NYM_API_VERSION}/mixnodes/active`;
|
||||
export const NYM_API_REWARDED_MIXNODES_PATH = `${NYM_API_VERSION}/mixnodes/rewarded`;
|
||||
|
||||
export interface IValidatorApiQuery {
|
||||
export interface INymApiQuery {
|
||||
getCachedMixnodes(): Promise<MixNodeBond[]>;
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]>;
|
||||
@@ -22,16 +22,16 @@ export interface IValidatorApiQuery {
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]>;
|
||||
}
|
||||
|
||||
export default class ValidatorApiQuerier implements IValidatorApiQuery {
|
||||
validatorApiUrl: string;
|
||||
export default class NymApiQuerier implements INymApiQuery {
|
||||
nymApiUrl: string;
|
||||
|
||||
constructor(validatorApiUrl: string) {
|
||||
this.validatorApiUrl = validatorApiUrl;
|
||||
constructor(nymApiUrl: string) {
|
||||
this.nymApiUrl = nymApiUrl;
|
||||
}
|
||||
|
||||
async getCachedMixnodes(): Promise<MixNodeBond[]> {
|
||||
const url = new URL(this.validatorApiUrl);
|
||||
url.pathname += VALIDATOR_API_MIXNODES_PATH;
|
||||
const url = new URL(this.nymApiUrl);
|
||||
url.pathname += NYM_API_MIXNODES_PATH;
|
||||
|
||||
const response = await axios.get(url.toString());
|
||||
if (response.status === 200) {
|
||||
@@ -41,8 +41,8 @@ export default class ValidatorApiQuerier implements IValidatorApiQuery {
|
||||
}
|
||||
|
||||
async getCachedGateways(): Promise<GatewayBond[]> {
|
||||
const url = new URL(this.validatorApiUrl);
|
||||
url.pathname += VALIDATOR_API_GATEWAYS_PATH;
|
||||
const url = new URL(this.nymApiUrl);
|
||||
url.pathname += NYM_API_GATEWAYS_PATH;
|
||||
|
||||
const response = await axios.get(url.toString());
|
||||
if (response.status === 200) {
|
||||
@@ -52,8 +52,8 @@ export default class ValidatorApiQuerier implements IValidatorApiQuery {
|
||||
}
|
||||
|
||||
async getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
const url = new URL(this.validatorApiUrl);
|
||||
url.pathname += VALIDATOR_API_ACTIVE_MIXNODES_PATH;
|
||||
const url = new URL(this.nymApiUrl);
|
||||
url.pathname += NYM_API_ACTIVE_MIXNODES_PATH;
|
||||
|
||||
const response = await axios.get(url.toString());
|
||||
if (response.status === 200) {
|
||||
@@ -63,8 +63,8 @@ export default class ValidatorApiQuerier implements IValidatorApiQuery {
|
||||
}
|
||||
|
||||
async getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
const url = new URL(this.validatorApiUrl);
|
||||
url.pathname += VALIDATOR_API_REWARDED_MIXNODES_PATH;
|
||||
const url = new URL(this.nymApiUrl);
|
||||
url.pathname += NYM_API_REWARDED_MIXNODES_PATH;
|
||||
|
||||
const response = await axios.get(url.toString());
|
||||
if (response.status === 200) {
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import ValidatorApiQuerier, { IValidatorApiQuery } from './validator-api-querier';
|
||||
import NymApiQuerier, { INymApiQuery as INymApiQuery } from './nym-api-querier';
|
||||
|
||||
export interface ICosmWasmQuery {
|
||||
// methods exposed by `CosmWasmClient`
|
||||
@@ -93,22 +93,22 @@ export interface INymdQuery {
|
||||
): Promise<RewardingStatus>;
|
||||
}
|
||||
|
||||
export interface IQueryClient extends ICosmWasmQuery, INymdQuery, IValidatorApiQuery {}
|
||||
export interface IQueryClient extends ICosmWasmQuery, INymdQuery, INymApiQuery { }
|
||||
|
||||
export default class QueryClient extends CosmWasmClient implements IQueryClient {
|
||||
private nymdQuerier: NymdQuerier;
|
||||
|
||||
private validatorApiQuerier: ValidatorApiQuerier;
|
||||
private nymApiQuerier: NymApiQuerier;
|
||||
|
||||
private constructor(tmClient: Tendermint34Client, validatorApiUrl: string) {
|
||||
private constructor(tmClient: Tendermint34Client, nymApiUrl: string) {
|
||||
super(tmClient);
|
||||
this.nymdQuerier = new NymdQuerier(this);
|
||||
this.validatorApiQuerier = new ValidatorApiQuerier(validatorApiUrl);
|
||||
this.nymApiQuerier = new NymApiQuerier(nymApiUrl);
|
||||
}
|
||||
|
||||
public static async connectWithNym(nymdUrl: string, validatorApiUrl: string): Promise<QueryClient> {
|
||||
public static async connectWithNym(nymdUrl: string, nymApiUrl: string): Promise<QueryClient> {
|
||||
const tmClient = await Tendermint34Client.connect(nymdUrl);
|
||||
return new QueryClient(tmClient, validatorApiUrl);
|
||||
return new QueryClient(tmClient, nymApiUrl);
|
||||
}
|
||||
|
||||
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion> {
|
||||
@@ -194,18 +194,18 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
|
||||
}
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]> {
|
||||
return this.validatorApiQuerier.getCachedGateways();
|
||||
return this.nymApiQuerier.getCachedGateways();
|
||||
}
|
||||
|
||||
getCachedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.validatorApiQuerier.getCachedMixnodes();
|
||||
return this.nymApiQuerier.getCachedMixnodes();
|
||||
}
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.validatorApiQuerier.getActiveMixnodes();
|
||||
return this.nymApiQuerier.getActiveMixnodes();
|
||||
}
|
||||
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.validatorApiQuerier.getRewardedMixnodes();
|
||||
return this.nymApiQuerier.getRewardedMixnodes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
PagedMixnodeResponse,
|
||||
RewardingStatus,
|
||||
} from './types';
|
||||
import ValidatorApiQuerier from './validator-api-querier';
|
||||
import NymApiQuerier from './nym-api-querier';
|
||||
|
||||
// methods exposed by `SigningCosmWasmClient`
|
||||
export interface ICosmWasmSigning {
|
||||
@@ -199,13 +199,13 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
|
||||
export default class SigningClient extends SigningCosmWasmClient implements ISigningClient {
|
||||
private nymdQuerier: NymdQuerier;
|
||||
|
||||
private validatorApiQuerier: ValidatorApiQuerier;
|
||||
private nymApiQuerier: NymApiQuerier;
|
||||
|
||||
clientAddress: string;
|
||||
|
||||
private constructor(
|
||||
clientAddress: string,
|
||||
validatorApiUrl: string,
|
||||
nymApiUrl: string,
|
||||
tmClient: Tendermint34Client,
|
||||
wallet: DirectSecp256k1HdWallet,
|
||||
signerOptions: SigningCosmWasmClientOptions,
|
||||
@@ -213,13 +213,13 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
super(tmClient, wallet, signerOptions);
|
||||
this.clientAddress = clientAddress;
|
||||
this.nymdQuerier = new NymdQuerier(this);
|
||||
this.validatorApiQuerier = new ValidatorApiQuerier(validatorApiUrl);
|
||||
this.nymApiQuerier = new NymApiQuerier(nymApiUrl);
|
||||
}
|
||||
|
||||
public static async connectWithNymSigner(
|
||||
wallet: DirectSecp256k1HdWallet,
|
||||
nymdUrl: string,
|
||||
validatorApiUrl: string,
|
||||
nymApiUrl: string,
|
||||
prefix: string,
|
||||
denom: string,
|
||||
): Promise<SigningClient> {
|
||||
@@ -229,7 +229,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
gasPrice: nymGasPrice(denom),
|
||||
};
|
||||
const tmClient = await Tendermint34Client.connect(nymdUrl);
|
||||
return new SigningClient(address, validatorApiUrl, tmClient, wallet, signerOptions);
|
||||
return new SigningClient(address, nymApiUrl, tmClient, wallet, signerOptions);
|
||||
}
|
||||
|
||||
// query related:
|
||||
@@ -317,19 +317,19 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
||||
}
|
||||
|
||||
getCachedGateways(): Promise<GatewayBond[]> {
|
||||
return this.validatorApiQuerier.getCachedGateways();
|
||||
return this.nymApiQuerier.getCachedGateways();
|
||||
}
|
||||
|
||||
getCachedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.validatorApiQuerier.getCachedMixnodes();
|
||||
return this.nymApiQuerier.getCachedMixnodes();
|
||||
}
|
||||
|
||||
getActiveMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.validatorApiQuerier.getActiveMixnodes();
|
||||
return this.nymApiQuerier.getActiveMixnodes();
|
||||
}
|
||||
|
||||
getRewardedMixnodes(): Promise<MixNodeBond[]> {
|
||||
return this.validatorApiQuerier.getRewardedMixnodes();
|
||||
return this.nymApiQuerier.getRewardedMixnodes();
|
||||
}
|
||||
|
||||
// signing related:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ValidatorClient from '../../dist';
|
||||
import ValidatorClient from '../../validator/index';
|
||||
import expect from 'expect';
|
||||
|
||||
describe('Query: balances', () => {
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct Config {
|
||||
/// ID specifies the human readable ID of this particular client.
|
||||
pub(crate) id: String,
|
||||
|
||||
pub(crate) validator_api_url: Url,
|
||||
pub(crate) nym_api_url: Url,
|
||||
|
||||
pub(crate) disabled_credentials_mode: bool,
|
||||
|
||||
@@ -38,7 +38,7 @@ impl Config {
|
||||
) -> Self {
|
||||
Config {
|
||||
id,
|
||||
validator_api_url: validator_server
|
||||
nym_api_url: validator_server
|
||||
.parse()
|
||||
.expect("provided url was malformed"),
|
||||
disabled_credentials_mode: true,
|
||||
|
||||
@@ -14,7 +14,7 @@ use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use rand::rngs::OsRng;
|
||||
use std::sync::Arc;
|
||||
use task::ShutdownNotifier;
|
||||
use task::TaskManager;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use wasm_utils::{console_error, console_log};
|
||||
@@ -30,7 +30,7 @@ pub struct NymClient {
|
||||
|
||||
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
||||
// and if it's dropped, everything will start going offline
|
||||
_shutdown: ShutdownNotifier,
|
||||
_task_manager: TaskManager,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -99,7 +99,7 @@ impl NymClientBuilder {
|
||||
self.bandwidth_controller,
|
||||
self.reply_surb_storage_backend,
|
||||
self.disabled_credentials,
|
||||
vec![self.config.validator_api_url.clone()],
|
||||
vec![self.config.nym_api_url.clone()],
|
||||
);
|
||||
|
||||
let self_address = base_builder.as_mix_recipient().to_string();
|
||||
@@ -121,7 +121,7 @@ impl NymClientBuilder {
|
||||
Ok(JsValue::from(NymClient {
|
||||
self_address,
|
||||
client_input: Arc::new(client_input),
|
||||
_shutdown: started_client.shutdown_notifier,
|
||||
_task_manager: started_client.task_manager,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ use rand::rngs::OsRng;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tungstenite::protocol::Message;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -67,7 +67,7 @@ pub struct GatewayClient {
|
||||
reconnection_backoff: Duration,
|
||||
|
||||
/// Listen to shutdown messages.
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl GatewayClient {
|
||||
@@ -83,7 +83,7 @@ impl GatewayClient {
|
||||
ack_sender: AcknowledgementSender,
|
||||
response_timeout_duration: Duration,
|
||||
bandwidth_controller: Option<BandwidthController<PersistentStorage>>,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
authenticated: false,
|
||||
@@ -135,7 +135,7 @@ impl GatewayClient {
|
||||
// perfectly fine here, because it's not meant to be used
|
||||
let (ack_tx, _) = mpsc::unbounded();
|
||||
let (mix_tx, _) = mpsc::unbounded();
|
||||
let shutdown = ShutdownListener::dummy();
|
||||
let shutdown = TaskClient::dummy();
|
||||
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
|
||||
|
||||
GatewayClient {
|
||||
@@ -305,11 +305,11 @@ impl GatewayClient {
|
||||
if let Some(shared_keys) = &self.shared_key {
|
||||
if let Some(plaintext) = try_decrypt_binary_message(bin_msg, shared_keys) {
|
||||
if let Err(err) = self.packet_router.route_received(vec![plaintext]) {
|
||||
log::warn!("Route received failed: {:?}", err);
|
||||
log::warn!("Route received failed: {err}");
|
||||
}
|
||||
}
|
||||
} else if let Err(err) = self.packet_router.route_received(vec![bin_msg]) {
|
||||
log::warn!("Route received failed: {:?}", err);
|
||||
log::warn!("Route received failed: {err}");
|
||||
}
|
||||
}
|
||||
Message::Text(txt_msg) => {
|
||||
|
||||
@@ -9,7 +9,7 @@ use futures::channel::mpsc;
|
||||
use log::*;
|
||||
use nymsphinx::addressing::nodes::MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
use nymsphinx::params::packet_sizes::PacketSize;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
|
||||
pub type MixnetMessageSender = mpsc::UnboundedSender<Vec<Vec<u8>>>;
|
||||
pub type MixnetMessageReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
|
||||
@@ -21,14 +21,14 @@ pub type AcknowledgementReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
|
||||
pub struct PacketRouter {
|
||||
ack_sender: AcknowledgementSender,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl PacketRouter {
|
||||
pub fn new(
|
||||
ack_sender: AcknowledgementSender,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Self {
|
||||
PacketRouter {
|
||||
ack_sender,
|
||||
@@ -89,14 +89,14 @@ impl PacketRouter {
|
||||
}
|
||||
// This should never happen during ordinary operation the way it's currently used.
|
||||
// Abort to be on the safe side
|
||||
panic!("Failed to send mixnet message: {:?}", err);
|
||||
panic!("Failed to send mixnet message: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
if !received_acks.is_empty() {
|
||||
trace!("routing acks");
|
||||
if let Err(e) = self.ack_sender.unbounded_send(received_acks) {
|
||||
error!("failed to send ack: {:?}", e);
|
||||
if let Err(err) = self.ack_sender.unbounded_send(received_acks) {
|
||||
error!("failed to send ack: {err}");
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -10,7 +10,7 @@ use futures::{SinkExt, StreamExt};
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use log::*;
|
||||
use std::sync::Arc;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tungstenite::Message;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -84,7 +84,7 @@ impl PartiallyDelegated {
|
||||
conn: WsConn,
|
||||
packet_router: PacketRouter,
|
||||
shared_key: Arc<SharedKeys>,
|
||||
mut shutdown: ShutdownListener,
|
||||
mut shutdown: TaskClient,
|
||||
) -> Self {
|
||||
// when called for, it NEEDS TO yield back the stream so that we could merge it and
|
||||
// read control request responses.
|
||||
@@ -100,7 +100,7 @@ impl PartiallyDelegated {
|
||||
|
||||
let ret_err = loop {
|
||||
tokio::select! {
|
||||
_ = shutdown.recv() => {
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("GatewayClient listener: Received shutdown");
|
||||
log::debug!("GatewayClient listener: Exiting");
|
||||
return;
|
||||
@@ -115,7 +115,7 @@ impl PartiallyDelegated {
|
||||
};
|
||||
|
||||
if let Err(err) = Self::route_socket_messages(ws_msgs, &mut packet_router, shared_key.as_ref()) {
|
||||
log::warn!("Route socket messages failed: {:?}", err);
|
||||
log::warn!("Route socket messages failed: {err}");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -122,7 +122,7 @@ impl Client {
|
||||
// We could have as well used conn.send_all(receiver.map(Ok)), but considering we don't care
|
||||
// about neither receiver nor the connection, it doesn't matter which one gets consumed
|
||||
if let Err(err) = receiver.map(Ok).forward(conn).await {
|
||||
warn!("Failed to forward packets to {} - {:?}", address, err);
|
||||
warn!("Failed to forward packets to {} - {err}", address);
|
||||
}
|
||||
|
||||
debug!(
|
||||
|
||||
@@ -59,7 +59,7 @@ impl PacketForwarder {
|
||||
self.mixnet_client
|
||||
.send_without_response(next_hop, sphinx_packet, packet_mode)
|
||||
{
|
||||
debug!("failed to forward the packet - {}", err)
|
||||
debug!("failed to forward the packet - {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ futures = "0.3"
|
||||
|
||||
coconut-interface = { path = "../../coconut-interface" }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests", features = ["coconut"] }
|
||||
nym-api-requests = { path = "../../../nym-api/nym-api-requests", features = ["coconut"] }
|
||||
|
||||
# required for nymd-client
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use crate::{nym_api, ValidatorClientError};
|
||||
use coconut_dkg_common::types::NodeIndex;
|
||||
use coconut_interface::VerificationKey;
|
||||
use mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use mixnet_contract_common::MixId;
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef};
|
||||
use validator_api_requests::coconut::{
|
||||
use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use validator_api_requests::models::{
|
||||
use nym_api_requests::models::{
|
||||
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
|
||||
RewardEstimationResponse, StakeSaturationResponse,
|
||||
};
|
||||
@@ -37,10 +37,10 @@ use mixnet_contract_common::{
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use network_defaults::NymNetworkDetails;
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use nym_api_requests::models::MixNodeBondAnnotated;
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use validator_api_requests::models::MixNodeBondAnnotated;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
#[must_use]
|
||||
@@ -142,7 +142,7 @@ pub struct Client<C> {
|
||||
proposals_page_limit: Option<u32>,
|
||||
|
||||
// ideally they would have been read-only, but unfortunately rust doesn't have such features
|
||||
pub validator_api: validator_api::Client,
|
||||
pub nym_api: nym_api::Client,
|
||||
pub nymd: NymdClient<C>,
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ impl Client<SigningNymdClient> {
|
||||
config: Config,
|
||||
mnemonic: bip39::Mnemonic,
|
||||
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||
config.nymd_config.clone(),
|
||||
config.nymd_url.as_str(),
|
||||
@@ -169,7 +169,7 @@ impl Client<SigningNymdClient> {
|
||||
dealers_page_limit: config.dealers_page_limit,
|
||||
verification_key_page_limit: config.verification_key_page_limit,
|
||||
proposals_page_limit: config.proposals_page_limit,
|
||||
validator_api: validator_api_client,
|
||||
nym_api: nym_api_client,
|
||||
nymd: nymd_client,
|
||||
})
|
||||
}
|
||||
@@ -192,7 +192,7 @@ impl Client<SigningNymdClient> {
|
||||
#[cfg(feature = "nymd-client")]
|
||||
impl Client<QueryNymdClient> {
|
||||
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let nymd_client =
|
||||
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
||||
|
||||
@@ -205,7 +205,7 @@ impl Client<QueryNymdClient> {
|
||||
dealers_page_limit: config.dealers_page_limit,
|
||||
verification_key_page_limit: config.verification_key_page_limit,
|
||||
proposals_page_limit: config.proposals_page_limit,
|
||||
validator_api: validator_api_client,
|
||||
nym_api: nym_api_client,
|
||||
nymd: nymd_client,
|
||||
})
|
||||
}
|
||||
@@ -731,53 +731,53 @@ impl<C> Client<C> {
|
||||
// validator-api wrappers
|
||||
#[cfg(feature = "nymd-client")]
|
||||
impl<C> Client<C> {
|
||||
pub fn change_validator_api(&mut self, new_endpoint: Url) {
|
||||
self.validator_api.change_url(new_endpoint)
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api.change_url(new_endpoint)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnodes().await?)
|
||||
Ok(self.nym_api.get_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnodes_detailed().await?)
|
||||
Ok(self.nym_api.get_mixnodes_detailed().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_rewarded_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
||||
Ok(self.nym_api.get_rewarded_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_rewarded_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_rewarded_mixnodes_detailed().await?)
|
||||
Ok(self.nym_api.get_rewarded_mixnodes_detailed().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_active_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_active_mixnodes().await?)
|
||||
Ok(self.nym_api.get_active_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_active_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_active_mixnodes_detailed().await?)
|
||||
Ok(self.nym_api.get_active_mixnodes_detailed().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_gateways().await?)
|
||||
Ok(self.nym_api.get_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
|
||||
Ok(self.validator_api.blind_sign(request_body).await?)
|
||||
Ok(self.nym_api.blind_sign(request_body).await?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,42 +827,40 @@ impl CoconutApiClient {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ApiClient {
|
||||
pub validator_api: validator_api::Client,
|
||||
pub nym_api_client: nym_api::Client,
|
||||
// TODO: perhaps if we really need it at some (currently I don't see any reasons for it)
|
||||
// we could re-implement the communication with the REST API on port 1317
|
||||
}
|
||||
|
||||
impl ApiClient {
|
||||
pub fn new(api_url: Url) -> Self {
|
||||
let validator_api_client = validator_api::Client::new(api_url);
|
||||
let nym_api_client = nym_api::Client::new(api_url);
|
||||
|
||||
ApiClient {
|
||||
validator_api: validator_api_client,
|
||||
}
|
||||
ApiClient { nym_api_client }
|
||||
}
|
||||
|
||||
pub fn change_validator_api(&mut self, new_endpoint: Url) {
|
||||
self.validator_api.change_url(new_endpoint);
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api_client.change_url(new_endpoint);
|
||||
}
|
||||
|
||||
pub async fn get_cached_active_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_active_mixnodes().await?)
|
||||
Ok(self.nym_api_client.get_active_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_rewarded_mixnodes(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_rewarded_mixnodes().await?)
|
||||
Ok(self.nym_api_client.get_rewarded_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnodes().await?)
|
||||
Ok(self.nym_api_client.get_mixnodes().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_gateways().await?)
|
||||
Ok(self.nym_api_client.get_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn get_gateway_core_status_count(
|
||||
@@ -871,7 +869,7 @@ impl ApiClient {
|
||||
since: Option<i64>,
|
||||
) -> Result<GatewayCoreStatusResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.nym_api_client
|
||||
.get_gateway_core_status_count(identity, since)
|
||||
.await?)
|
||||
}
|
||||
@@ -882,7 +880,7 @@ impl ApiClient {
|
||||
since: Option<i64>,
|
||||
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.nym_api_client
|
||||
.get_mixnode_core_status_count(mix_id, since)
|
||||
.await?)
|
||||
}
|
||||
@@ -891,7 +889,7 @@ impl ApiClient {
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
|
||||
Ok(self.validator_api.get_mixnode_status(mix_id).await?)
|
||||
Ok(self.nym_api_client.get_mixnode_status(mix_id).await?)
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_reward_estimation(
|
||||
@@ -899,7 +897,7 @@ impl ApiClient {
|
||||
mix_id: MixId,
|
||||
) -> Result<RewardEstimationResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.nym_api_client
|
||||
.get_mixnode_reward_estimation(mix_id)
|
||||
.await?)
|
||||
}
|
||||
@@ -909,7 +907,7 @@ impl ApiClient {
|
||||
mix_id: MixId,
|
||||
) -> Result<StakeSaturationResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.nym_api_client
|
||||
.get_mixnode_stake_saturation(mix_id)
|
||||
.await?)
|
||||
}
|
||||
@@ -918,7 +916,7 @@ impl ApiClient {
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
|
||||
Ok(self.validator_api.blind_sign(request_body).await?)
|
||||
Ok(self.nym_api_client.blind_sign(request_body).await?)
|
||||
}
|
||||
|
||||
pub async fn partial_bandwidth_credential(
|
||||
@@ -926,7 +924,7 @@ impl ApiClient {
|
||||
request_body: &str,
|
||||
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.nym_api_client
|
||||
.partial_bandwidth_credential(request_body)
|
||||
.await?)
|
||||
}
|
||||
@@ -936,7 +934,7 @@ impl ApiClient {
|
||||
request_body: &VerifyCredentialBody,
|
||||
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
|
||||
Ok(self
|
||||
.validator_api
|
||||
.nym_api_client
|
||||
.verify_bandwidth_credential(request_body)
|
||||
.await?)
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ async fn test_nymd_connection(
|
||||
log::debug!("Checking: nymd_url: {url}: {}: {}", "failed".red(), e);
|
||||
false
|
||||
}
|
||||
Ok(Err(NymdError::AbciError { code, log, .. })) => {
|
||||
Ok(Err(NymdError::AbciError(code, log))) => {
|
||||
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
|
||||
// for example on a pre-launch network.
|
||||
log::debug!(
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::validator_api;
|
||||
use crate::nym_api;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ValidatorClientError {
|
||||
#[error("There was an issue with the validator api request - {source}")]
|
||||
ValidatorAPIError {
|
||||
NymAPIError {
|
||||
#[from]
|
||||
source: validator_api::error::ValidatorAPIError,
|
||||
source: nym_api::error::NymAPIError,
|
||||
},
|
||||
|
||||
#[error("One of the provided URLs was malformed - {0}")]
|
||||
|
||||
@@ -5,14 +5,14 @@ pub mod client;
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub mod connection_tester;
|
||||
mod error;
|
||||
pub mod nym_api;
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub mod nymd;
|
||||
pub mod validator_api;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub use crate::client::{ApiClient, CoconutApiClient};
|
||||
pub use crate::error::ValidatorClientError;
|
||||
pub use validator_api_requests::*;
|
||||
pub use nym_api_requests::*;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub use client::{Client, Config};
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
use nym_api_requests::models::RequestError;
|
||||
use thiserror::Error;
|
||||
use validator_api_requests::models::RequestError;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ValidatorAPIError {
|
||||
pub enum NymAPIError {
|
||||
#[error("There was an issue with the REST request - {source}")]
|
||||
ReqwestClientError {
|
||||
#[from]
|
||||
@@ -12,6 +12,6 @@ pub enum ValidatorAPIError {
|
||||
#[error("Request failed with error message - {0}")]
|
||||
GenericRequestFailure(String),
|
||||
|
||||
#[error("The validator API has failed to resolve our request. It returned status code {status} and additional error message: {}", error.message())]
|
||||
#[error("The nym API has failed to resolve our request. It returned status code {status} and additional error message: {}", error.message())]
|
||||
ApiRequestFailure { status: u16, error: RequestError },
|
||||
}
|
||||
+65
-89
@@ -1,23 +1,22 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::validator_api::error::ValidatorAPIError;
|
||||
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||
use crate::nym_api::error::NymAPIError;
|
||||
use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||
use mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
|
||||
use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
GatewayCoreStatusResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse,
|
||||
InclusionProbabilityResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
|
||||
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RequestError,
|
||||
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
|
||||
};
|
||||
use reqwest::Response;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
use validator_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use validator_api_requests::models::{
|
||||
ComputeRewardEstParam, GatewayCoreStatusResponse, GatewayStatusReportResponse,
|
||||
GatewayUptimeHistoryResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
|
||||
MixnodeCoreStatusResponse, MixnodeStatusReportResponse, MixnodeStatusResponse,
|
||||
MixnodeUptimeHistoryResponse, RequestError, RewardEstimationResponse, StakeSaturationResponse,
|
||||
UptimeResponse,
|
||||
};
|
||||
|
||||
pub mod error;
|
||||
pub mod routes;
|
||||
@@ -54,7 +53,7 @@ impl Client {
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<Response, ValidatorAPIError>
|
||||
) -> Result<Response, NymAPIError>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
@@ -63,11 +62,11 @@ impl Client {
|
||||
Ok(self.reqwest_client.get(url).send().await?)
|
||||
}
|
||||
|
||||
async fn query_validator_api<T, K, V>(
|
||||
async fn query_nym_api<T, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, ValidatorAPIError>
|
||||
) -> Result<T, NymAPIError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
@@ -77,16 +76,16 @@ impl Client {
|
||||
if res.status().is_success() {
|
||||
Ok(res.json().await?)
|
||||
} else {
|
||||
Err(ValidatorAPIError::GenericRequestFailure(res.text().await?))
|
||||
Err(NymAPIError::GenericRequestFailure(res.text().await?))
|
||||
}
|
||||
}
|
||||
|
||||
// This works for endpoints returning Result<Json<T>, ErrorResponse>
|
||||
async fn query_validator_api_fallible<T, K, V>(
|
||||
async fn query_nym_api_fallible<T, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, ValidatorAPIError>
|
||||
) -> Result<T, NymAPIError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
@@ -98,19 +97,19 @@ impl Client {
|
||||
Ok(res.json().await?)
|
||||
} else {
|
||||
let request_error: RequestError = res.json().await?;
|
||||
Err(ValidatorAPIError::ApiRequestFailure {
|
||||
Err(NymAPIError::ApiRequestFailure {
|
||||
status: status.as_u16(),
|
||||
error: request_error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn post_validator_api<B, T, K, V>(
|
||||
async fn post_nym_api<B, T, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, ValidatorAPIError>
|
||||
) -> Result<T, NymAPIError>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
@@ -122,21 +121,17 @@ impl Client {
|
||||
if response.status().is_success() {
|
||||
Ok(response.json().await?)
|
||||
} else {
|
||||
Err(ValidatorAPIError::GenericRequestFailure(
|
||||
response.text().await?,
|
||||
))
|
||||
Err(NymAPIError::GenericRequestFailure(response.text().await?))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorAPIError> {
|
||||
self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
|
||||
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.query_nym_api(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
pub async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -148,13 +143,13 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> {
|
||||
self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
|
||||
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
|
||||
self.query_nym_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
|
||||
NO_PARAMS,
|
||||
)
|
||||
@@ -163,8 +158,8 @@ impl Client {
|
||||
|
||||
pub async fn get_active_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -177,8 +172,8 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
|
||||
NO_PARAMS,
|
||||
)
|
||||
@@ -188,8 +183,8 @@ impl Client {
|
||||
pub async fn get_mixnode_report(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeStatusReportResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -205,8 +200,8 @@ impl Client {
|
||||
pub async fn get_gateway_report(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<GatewayStatusReportResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<GatewayStatusReportResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -222,8 +217,8 @@ impl Client {
|
||||
pub async fn get_mixnode_history(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeUptimeHistoryResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -239,8 +234,8 @@ impl Client {
|
||||
pub async fn get_gateway_history(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<GatewayUptimeHistoryResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<GatewayUptimeHistoryResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -255,8 +250,8 @@ impl Client {
|
||||
|
||||
pub async fn get_rewarded_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -273,9 +268,9 @@ impl Client {
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
since: Option<i64>,
|
||||
) -> Result<GatewayCoreStatusResponse, ValidatorAPIError> {
|
||||
) -> Result<GatewayCoreStatusResponse, NymAPIError> {
|
||||
if let Some(since) = since {
|
||||
self.query_validator_api(
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -287,7 +282,7 @@ impl Client {
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
self.query_validator_api(
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -304,9 +299,9 @@ impl Client {
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
since: Option<i64>,
|
||||
) -> Result<MixnodeCoreStatusResponse, ValidatorAPIError> {
|
||||
) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
|
||||
if let Some(since) = since {
|
||||
self.query_validator_api(
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -318,7 +313,7 @@ impl Client {
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
self.query_validator_api(
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -335,8 +330,8 @@ impl Client {
|
||||
pub async fn get_mixnode_status(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeStatusResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
) -> Result<MixnodeStatusResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -352,8 +347,8 @@ impl Client {
|
||||
pub async fn get_mixnode_reward_estimation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<RewardEstimationResponse, ValidatorAPIError> {
|
||||
self.query_validator_api_fallible(
|
||||
) -> Result<RewardEstimationResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -366,30 +361,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn compute_mixnode_reward_estimation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
request_body: &ComputeRewardEstParam,
|
||||
) -> Result<RewardEstimationResponse, ValidatorAPIError> {
|
||||
self.post_validator_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
routes::MIXNODE,
|
||||
&mix_id.to_string(),
|
||||
routes::COMPUTE_REWARD_ESTIMATION,
|
||||
],
|
||||
NO_PARAMS,
|
||||
request_body,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_stake_saturation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<StakeSaturationResponse, ValidatorAPIError> {
|
||||
self.query_validator_api_fallible(
|
||||
) -> Result<StakeSaturationResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -405,8 +381,8 @@ impl Client {
|
||||
pub async fn get_mixnode_inclusion_probability(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<InclusionProbabilityResponse, ValidatorAPIError> {
|
||||
self.query_validator_api_fallible(
|
||||
) -> Result<InclusionProbabilityResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -422,8 +398,8 @@ impl Client {
|
||||
pub async fn get_mixnode_avg_uptime(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<UptimeResponse, ValidatorAPIError> {
|
||||
self.query_validator_api_fallible(
|
||||
) -> Result<UptimeResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -439,8 +415,8 @@ impl Client {
|
||||
pub async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
|
||||
self.post_validator_api(
|
||||
) -> Result<BlindedSignatureResponse, NymAPIError> {
|
||||
self.post_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
@@ -456,8 +432,8 @@ impl Client {
|
||||
pub async fn partial_bandwidth_credential(
|
||||
&self,
|
||||
request_body: &str,
|
||||
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
|
||||
self.post_validator_api(
|
||||
) -> Result<BlindedSignatureResponse, NymAPIError> {
|
||||
self.post_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
@@ -473,8 +449,8 @@ impl Client {
|
||||
pub async fn verify_bandwidth_credential(
|
||||
&self,
|
||||
request_body: &VerifyCredentialBody,
|
||||
) -> Result<VerifyCredentialResponse, ValidatorAPIError> {
|
||||
self.post_validator_api(
|
||||
) -> Result<VerifyCredentialResponse, NymAPIError> {
|
||||
self.post_nym_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
+2
-3
@@ -1,9 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use network_defaults::VALIDATOR_API_VERSION;
|
||||
use network_defaults::NYM_API_VERSION;
|
||||
|
||||
pub const API_VERSION: &str = VALIDATOR_API_VERSION;
|
||||
pub const API_VERSION: &str = NYM_API_VERSION;
|
||||
pub const MIXNODES: &str = "mixnodes";
|
||||
pub const GATEWAYS: &str = "gateways";
|
||||
|
||||
@@ -28,7 +28,6 @@ pub const STATUS: &str = "status";
|
||||
pub const REPORT: &str = "report";
|
||||
pub const HISTORY: &str = "history";
|
||||
pub const REWARD_ESTIMATION: &str = "reward-estimation";
|
||||
pub const COMPUTE_REWARD_ESTIMATION: &str = "compute-reward-estimation";
|
||||
pub const AVG_UPTIME: &str = "avg_uptime";
|
||||
pub const STAKE_SATURATION: &str = "stake-saturation";
|
||||
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd;
|
||||
use crate::nymd::coin::Coin;
|
||||
use crate::nymd::cosmwasm_client::helpers::{create_pagination, next_page_key};
|
||||
use crate::nymd::cosmwasm_client::types::{
|
||||
@@ -24,6 +23,7 @@ use cosmrs::rpc::endpoint::broadcast;
|
||||
use cosmrs::rpc::endpoint::tx::Response as TxResponse;
|
||||
use cosmrs::rpc::query::Query;
|
||||
use cosmrs::rpc::{self, HttpClient, Order};
|
||||
use cosmrs::tendermint::abci::Code as AbciCode;
|
||||
use cosmrs::tendermint::abci::Transaction;
|
||||
use cosmrs::tendermint::{abci, block, chain};
|
||||
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Tx};
|
||||
@@ -66,9 +66,13 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
req.encode(&mut buf)?;
|
||||
|
||||
let res = self.abci_query(path, buf, None, false).await?;
|
||||
let res_success = nymd::error::parse_abci_query_result(res)?;
|
||||
|
||||
Ok(Res::decode(res_success.value.as_ref())?)
|
||||
match res.code {
|
||||
AbciCode::Err(code) => return Err(NymdError::AbciError(code, res.log)),
|
||||
AbciCode::Ok => (),
|
||||
}
|
||||
|
||||
Ok(Res::decode(res.value.as_ref())?)
|
||||
}
|
||||
|
||||
async fn get_chain_id(&self) -> Result<chain::Id, NymdError> {
|
||||
|
||||
@@ -2,23 +2,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd::cosmwasm_client::types::ContractCodeId;
|
||||
use cosmrs::{
|
||||
bip32,
|
||||
rpc::endpoint::abci_query::AbciQuery,
|
||||
tendermint::{
|
||||
abci::{self, Code as AbciCode},
|
||||
block,
|
||||
},
|
||||
tx, AccountId,
|
||||
};
|
||||
use cosmrs::tendermint::{abci, block};
|
||||
use cosmrs::{bip32, tx, AccountId};
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
|
||||
use std::{io, time::Duration};
|
||||
|
||||
pub use cosmrs::rpc::{
|
||||
error::{Error as TendermintRpcError, ErrorDetail as TendermintRpcErrorDetail},
|
||||
response_error::{Code, ResponseError},
|
||||
pub use cosmrs::rpc::error::{
|
||||
Error as TendermintRpcError, ErrorDetail as TendermintRpcErrorDetail,
|
||||
};
|
||||
pub use cosmrs::rpc::response_error::{Code, ResponseError};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NymdError {
|
||||
@@ -117,12 +110,8 @@ pub enum NymdError {
|
||||
#[error("Failed to estimate gas price for the transaction")]
|
||||
GasEstimationFailure,
|
||||
|
||||
#[error("Abci query failed with code {code} - {log}")]
|
||||
AbciError {
|
||||
code: u32,
|
||||
log: abci::Log,
|
||||
pretty_log: Option<String>,
|
||||
},
|
||||
#[error("Abci query failed with code {0} - {1}")]
|
||||
AbciError(u32, abci::Log),
|
||||
|
||||
#[error("Unsupported account type: {type_url}")]
|
||||
UnsupportedAccountType { type_url: String },
|
||||
@@ -146,32 +135,6 @@ pub enum NymdError {
|
||||
UnexpectedBech32Prefix { got: String, expected: String },
|
||||
}
|
||||
|
||||
// The purpose of parsing the abci query result is that we want to generate the `pretty_log` if
|
||||
// possible.
|
||||
pub fn parse_abci_query_result(query_result: AbciQuery) -> Result<AbciQuery, NymdError> {
|
||||
match query_result.code {
|
||||
AbciCode::Ok => Ok(query_result),
|
||||
AbciCode::Err(code) => Err(NymdError::AbciError {
|
||||
code,
|
||||
log: query_result.log.clone(),
|
||||
pretty_log: try_parse_abci_log(&query_result.log),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// Some of the error strings returned by the query are a bit too technical to present to the
|
||||
// enduser. So we special case some commonly encountered errors.
|
||||
fn try_parse_abci_log(log: &abci::Log) -> Option<String> {
|
||||
if log
|
||||
.value()
|
||||
.contains("Maximum amount of locked coins has already been pledged")
|
||||
{
|
||||
Some("Maximum amount of locked tokens has alredy been used. You can only use up to 10% of your locked tokens for bonding and delegating.".to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl NymdError {
|
||||
pub fn is_tendermint_response_timeout(&self) -> bool {
|
||||
match &self {
|
||||
|
||||
@@ -16,9 +16,9 @@ pub enum ContextError {
|
||||
#[error("failed to create client - {0}")]
|
||||
NymdError(String),
|
||||
|
||||
#[error("{0}")]
|
||||
#[error(transparent)]
|
||||
NymdErrorPassthrough(#[from] validator_client::nymd::error::NymdError),
|
||||
|
||||
#[error("{0}")]
|
||||
#[error(transparent)]
|
||||
ValidatorClientError(#[from] validator_client::ValidatorClientError),
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ use network_defaults::{
|
||||
NymNetworkDetails,
|
||||
};
|
||||
use tap::prelude::*;
|
||||
pub use validator_client::nym_api::Client as NymApiClient;
|
||||
use validator_client::nymd::{self, AccountId, NymdClient, QueryNymdClient, SigningNymdClient};
|
||||
pub use validator_client::validator_api::Client as ValidatorApiClient;
|
||||
|
||||
use crate::context::errors::ContextError;
|
||||
|
||||
@@ -16,14 +16,14 @@ pub mod errors;
|
||||
|
||||
pub type SigningClient = validator_client::nymd::NymdClient<SigningNymdClient>;
|
||||
pub type QueryClient = validator_client::nymd::NymdClient<QueryNymdClient>;
|
||||
pub type SigningClientWithValidatorAPI = validator_client::Client<SigningNymdClient>;
|
||||
pub type QueryClientWithValidatorAPI = validator_client::Client<QueryNymdClient>;
|
||||
pub type SigningClientWithNymd = validator_client::Client<SigningNymdClient>;
|
||||
pub type QueryClientWithNymd = validator_client::Client<QueryNymdClient>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClientArgs {
|
||||
pub config_env_file: Option<std::path::PathBuf>,
|
||||
pub nymd_url: Option<String>,
|
||||
pub validator_api_url: Option<String>,
|
||||
pub nym_api_url: Option<String>,
|
||||
pub mnemonic: Option<bip39::Mnemonic>,
|
||||
pub mixnet_contract_address: Option<AccountId>,
|
||||
pub vesting_contract_address: Option<AccountId>,
|
||||
@@ -38,8 +38,8 @@ pub fn get_network_details(args: &ClientArgs) -> Result<NymNetworkDetails, Conte
|
||||
if let Some(nymd_url) = args.nymd_url.as_ref() {
|
||||
std::env::set_var(NYMD_VALIDATOR, nymd_url);
|
||||
}
|
||||
if let Some(validator_api_url) = args.validator_api_url.as_ref() {
|
||||
std::env::set_var(API_VALIDATOR, validator_api_url);
|
||||
if let Some(nym_api_url) = args.nym_api_url.as_ref() {
|
||||
std::env::set_var(API_VALIDATOR, nym_api_url);
|
||||
}
|
||||
if let Some(mixnet_contract_address) = args.mixnet_contract_address.as_ref() {
|
||||
std::env::set_var(MIXNET_CONTRACT_ADDRESS, mixnet_contract_address.to_string());
|
||||
@@ -59,7 +59,7 @@ pub fn create_signing_client(
|
||||
network_details: &NymNetworkDetails,
|
||||
) -> Result<SigningClient, ContextError> {
|
||||
let client_config = nymd::Config::try_from_nym_network_details(network_details)
|
||||
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
|
||||
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
|
||||
|
||||
// get mnemonic
|
||||
let mnemonic = match std::env::var("MNEMONIC") {
|
||||
@@ -88,7 +88,7 @@ pub fn create_query_client(
|
||||
network_details: &NymNetworkDetails,
|
||||
) -> Result<QueryClient, ContextError> {
|
||||
let client_config = nymd::Config::try_from_nym_network_details(network_details)
|
||||
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
|
||||
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
|
||||
|
||||
let nymd_url = network_details
|
||||
.endpoints
|
||||
@@ -103,12 +103,12 @@ pub fn create_query_client(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_signing_client_with_validator_api(
|
||||
pub fn create_signing_client_with_nym_api(
|
||||
args: ClientArgs,
|
||||
network_details: &NymNetworkDetails,
|
||||
) -> Result<SigningClientWithValidatorAPI, ContextError> {
|
||||
) -> Result<SigningClientWithNymd, ContextError> {
|
||||
let client_config = validator_client::Config::try_from_nym_network_details(network_details)
|
||||
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
|
||||
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
|
||||
|
||||
// get mnemonic
|
||||
let mnemonic = match std::env::var("MNEMONIC") {
|
||||
@@ -126,11 +126,11 @@ pub fn create_signing_client_with_validator_api(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_query_client_with_validator_api(
|
||||
pub fn create_query_client_with_nym_api(
|
||||
network_details: &NymNetworkDetails,
|
||||
) -> Result<QueryClientWithValidatorAPI, ContextError> {
|
||||
) -> Result<QueryClientWithNymd, ContextError> {
|
||||
let client_config = validator_client::Config::try_from_nym_network_details(network_details)
|
||||
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
|
||||
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
|
||||
|
||||
match validator_client::client::Client::new_query(client_config) {
|
||||
Ok(client) => Ok(client),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
|
||||
use crate::context::SigningClientWithValidatorAPI;
|
||||
use crate::context::SigningClientWithNymd;
|
||||
use crate::utils::{pretty_cosmwasm_coin, show_error_passthrough};
|
||||
|
||||
use comfy_table::Table;
|
||||
@@ -14,7 +14,7 @@ use mixnet_contract_common::{Delegation, PendingEpochEvent, PendingEpochEventKin
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {}
|
||||
|
||||
pub async fn execute(_args: Args, client: SigningClientWithValidatorAPI) {
|
||||
pub async fn execute(_args: Args, client: SigningClientWithNymd) {
|
||||
info!(
|
||||
"Getting delegations for account {}...",
|
||||
client.nymd.address()
|
||||
@@ -48,14 +48,14 @@ pub async fn execute(_args: Args, client: SigningClientWithValidatorAPI) {
|
||||
}
|
||||
}
|
||||
|
||||
async fn to_iso_timestamp(block_height: u32, client: &SigningClientWithValidatorAPI) -> String {
|
||||
async fn to_iso_timestamp(block_height: u32, client: &SigningClientWithNymd) -> String {
|
||||
match client.nymd.get_block_timestamp(Some(block_height)).await {
|
||||
Ok(res) => res.to_rfc3339(),
|
||||
Err(_e) => "-".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientWithValidatorAPI) {
|
||||
async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientWithNymd) {
|
||||
let mut table = Table::new();
|
||||
|
||||
table.set_header(vec!["Timestamp", "Mix Id", "Delegation", "Proxy"]);
|
||||
@@ -75,10 +75,7 @@ async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientW
|
||||
println!("{table}");
|
||||
}
|
||||
|
||||
async fn print_delegation_events(
|
||||
events: Vec<PendingEpochEvent>,
|
||||
client: &SigningClientWithValidatorAPI,
|
||||
) {
|
||||
async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &SigningClientWithNymd) {
|
||||
let mut table = Table::new();
|
||||
|
||||
table.set_header(vec![
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
|
||||
use crate::context::QueryClientWithValidatorAPI;
|
||||
use crate::context::QueryClientWithNymd;
|
||||
use crate::utils::{pretty_cosmwasm_coin, show_error};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -14,8 +14,8 @@ pub struct Args {
|
||||
pub identity_key: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn query(args: Args, client: &QueryClientWithValidatorAPI) {
|
||||
match client.validator_api.get_gateways().await {
|
||||
pub async fn query(args: Args, client: &QueryClientWithNymd) {
|
||||
match client.nym_api.get_gateways().await {
|
||||
Ok(res) => match args.identity_key {
|
||||
Some(identity_key) => {
|
||||
let node = res.iter().find(|node| {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
|
||||
use crate::context::QueryClientWithValidatorAPI;
|
||||
use crate::context::QueryClientWithNymd;
|
||||
use crate::utils::{pretty_decimal_with_denom, show_error};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -14,8 +14,8 @@ pub struct Args {
|
||||
pub identity_key: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn query(args: Args, client: &QueryClientWithValidatorAPI) {
|
||||
match client.validator_api.get_mixnodes().await {
|
||||
pub async fn query(args: Args, client: &QueryClientWithNymd) {
|
||||
match client.nym_api.get_mixnodes().await {
|
||||
Ok(res) => match args.identity_key {
|
||||
Some(identity_key) => {
|
||||
let node = res.iter().find(|node| {
|
||||
|
||||
@@ -11,6 +11,6 @@ pub enum Errors {
|
||||
#[error("signature error - {0}")]
|
||||
SignatureError(#[from] k256::ecdsa::signature::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
#[error(transparent)]
|
||||
CosmrsError(#[from] cosmrs::ErrorReport),
|
||||
}
|
||||
|
||||
@@ -45,13 +45,13 @@ impl PersistentStorage {
|
||||
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
|
||||
Ok(db) => db,
|
||||
Err(err) => {
|
||||
error!("Failed to connect to SQLx database: {}", err);
|
||||
error!("Failed to connect to SQLx database: {err}");
|
||||
return Err(err.into());
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = sqlx::migrate!("./migrations").run(&connection_pool).await {
|
||||
error!("Failed to perform migration on the SQLx database: {}", err);
|
||||
error!("Failed to perform migration on the SQLx database: {err}");
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ impl Storage for PersistentStorage {
|
||||
|
||||
pub async fn initialise_storage(path: PathBuf) -> PersistentStorage {
|
||||
match PersistentStorage::init(path).await {
|
||||
Err(err) => panic!("failed to initialise credential storage - {}", err),
|
||||
Err(err) => panic!("failed to initialise credential storage - {err}"),
|
||||
Ok(storage) => storage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ thiserror = "1.0"
|
||||
# I guess temporarily until we get serde support in coconut up and running
|
||||
coconut-interface = { path = "../coconut-interface" }
|
||||
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
||||
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
|
||||
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
validator-client = { path = "../client-libs/validator-client" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -9,7 +9,7 @@ type Aes128Ctr = ctr::Ctr64LE<Aes128>;
|
||||
|
||||
/// Hashing algorithm used during hkdf for ephemeral shared key generation per blinded signature
|
||||
/// response encryption.
|
||||
pub type ValidatorApiCredentialHkdfAlgorithm = blake3::Hasher;
|
||||
pub type NymApiCredentialHkdfAlgorithm = blake3::Hasher;
|
||||
|
||||
/// Encryption algorithm used for end-to-end encryption of blinded signature response
|
||||
pub type ValidatorApiCredentialEncryptionAlgorithm = Aes128Ctr;
|
||||
pub type NymApiCredentialEncryptionAlgorithm = Aes128Ctr;
|
||||
|
||||
@@ -8,13 +8,11 @@ use coconut_interface::{
|
||||
use crypto::asymmetric::encryption::PublicKey;
|
||||
use crypto::shared_key::recompute_shared_key;
|
||||
use crypto::symmetric::stream_cipher;
|
||||
use validator_api_requests::coconut::BlindSignRequestBody;
|
||||
use nym_api_requests::coconut::BlindSignRequestBody;
|
||||
use validator_client::client::CoconutApiClient;
|
||||
|
||||
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
|
||||
use crate::coconut::params::{
|
||||
ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm,
|
||||
};
|
||||
use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm};
|
||||
use crate::error::Error;
|
||||
|
||||
pub async fn obtain_aggregate_verification_key(
|
||||
@@ -66,11 +64,11 @@ async fn obtain_partial_credential(
|
||||
let remote_key = PublicKey::from_bytes(&response.remote_key)?;
|
||||
|
||||
let encryption_key = recompute_shared_key::<
|
||||
ValidatorApiCredentialEncryptionAlgorithm,
|
||||
ValidatorApiCredentialHkdfAlgorithm,
|
||||
NymApiCredentialEncryptionAlgorithm,
|
||||
NymApiCredentialHkdfAlgorithm,
|
||||
>(&remote_key, attributes.encryption_key());
|
||||
let zero_iv = stream_cipher::zero_iv::<ValidatorApiCredentialEncryptionAlgorithm>();
|
||||
let blinded_signature_bytes = stream_cipher::decrypt::<ValidatorApiCredentialEncryptionAlgorithm>(
|
||||
let zero_iv = stream_cipher::zero_iv::<NymApiCredentialEncryptionAlgorithm>();
|
||||
let blinded_signature_bytes = stream_cipher::decrypt::<NymApiCredentialEncryptionAlgorithm>(
|
||||
&encryption_key,
|
||||
&zero_iv,
|
||||
&encrypted_signature,
|
||||
|
||||
@@ -22,6 +22,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"], optional = true }
|
||||
serde_bytes = { version = "0.11.6", optional = true }
|
||||
serde_crate = { version = "1.0", optional = true, default_features = false, package = "serde" }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
|
||||
thiserror = "1.0.37"
|
||||
|
||||
# internal
|
||||
nymsphinx-types = { path = "../nymsphinx/types" }
|
||||
|
||||
@@ -326,11 +326,6 @@ pub fn try_recover_verification_keys(
|
||||
return Err(DkgError::MismatchedDealings);
|
||||
}
|
||||
|
||||
// currently we expect every dealer to also be a receiver. This restriction might be relaxed in the future
|
||||
if dealings.len() != receivers.len() {
|
||||
return Err(DkgError::MismatchedDealings);
|
||||
}
|
||||
|
||||
let indices = receivers.keys().collect::<Vec<_>>();
|
||||
|
||||
// Compute A0, ..., A_{t-1}
|
||||
|
||||
@@ -254,3 +254,125 @@ fn full_threshold_secret_resharing() {
|
||||
assert_ne!(derived_secrets, reshared_secrets);
|
||||
assert_ne!(recovered_partials, reshared_partials);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // expensive test
|
||||
fn full_threshold_secret_resharing_left_party() {
|
||||
let dummy_seed = [42u8; 32];
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||
let params = setup();
|
||||
|
||||
// the simplest possible case
|
||||
let threshold = 2;
|
||||
|
||||
// the indices are going to get assigned externally, so for test sake, use non-consecutive ones
|
||||
let mut node_indices = vec![15u64, 248, 33521];
|
||||
|
||||
let mut receivers = BTreeMap::new();
|
||||
let mut full_keys = Vec::new();
|
||||
for index in &node_indices {
|
||||
let (dk, pk) = keygen(¶ms, &mut rng);
|
||||
receivers.insert(*index, *pk.public_key());
|
||||
full_keys.push((dk, pk))
|
||||
}
|
||||
|
||||
let first_dealings = node_indices
|
||||
.iter()
|
||||
.map(|&dealer_index| {
|
||||
Dealing::create(&mut rng, ¶ms, dealer_index, threshold, &receivers, None).0
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// recover verification keys
|
||||
let RecoveredVerificationKeys {
|
||||
recovered_master: public_original_master,
|
||||
recovered_partials,
|
||||
} = try_recover_verification_keys(&first_dealings, threshold, &receivers).unwrap();
|
||||
|
||||
let mut derived_secrets = Vec::new();
|
||||
for (i, (ref mut dk, _)) in full_keys.iter_mut().enumerate() {
|
||||
let shares = first_dealings
|
||||
.iter()
|
||||
.map(|dealing| decrypt_share(dk, i, &dealing.ciphertexts, None).unwrap())
|
||||
.collect();
|
||||
|
||||
let recovered_secret =
|
||||
combine_shares(shares, &receivers.keys().copied().collect::<Vec<_>>()).unwrap();
|
||||
|
||||
derived_secrets.push(recovered_secret)
|
||||
}
|
||||
|
||||
let original_master = perform_lagrangian_interpolation_at_origin(&[
|
||||
(Scalar::from(node_indices[0]), derived_secrets[0]),
|
||||
(Scalar::from(node_indices[1]), derived_secrets[1]),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
// one party leaves the process
|
||||
let left_party_index = node_indices.pop().unwrap();
|
||||
receivers.remove(&left_party_index);
|
||||
full_keys.pop();
|
||||
// and another one joins, but we're still over the threshold value of initial parties
|
||||
let join_party_index = 100000;
|
||||
let (dk, pk) = keygen(¶ms, &mut rng);
|
||||
receivers.insert(join_party_index, *pk.public_key());
|
||||
full_keys.push((dk, pk));
|
||||
|
||||
// only initial parties attempt to create resharing dealings!
|
||||
let resharing_dealings = node_indices
|
||||
.iter()
|
||||
.zip(derived_secrets.iter().take(2))
|
||||
.map(|(&dealer_index, prior_secret)| {
|
||||
Dealing::create(
|
||||
&mut rng,
|
||||
¶ms,
|
||||
dealer_index,
|
||||
threshold,
|
||||
&receivers,
|
||||
Some(*prior_secret),
|
||||
)
|
||||
.0
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (reshared_dealing, prior_vk) in resharing_dealings
|
||||
.iter()
|
||||
.zip(recovered_partials.iter().take(2))
|
||||
{
|
||||
reshared_dealing
|
||||
.verify(¶ms, threshold, &receivers, Some(*prior_vk))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// recover verification keys
|
||||
let RecoveredVerificationKeys {
|
||||
recovered_master: public_reshared_master,
|
||||
recovered_partials: reshared_partials,
|
||||
} = try_recover_verification_keys(&resharing_dealings, threshold, &receivers).unwrap();
|
||||
|
||||
let mut reshared_secrets = Vec::new();
|
||||
for (i, (ref mut dk, _)) in full_keys.iter_mut().enumerate() {
|
||||
let shares = resharing_dealings
|
||||
.iter()
|
||||
.map(|dealing| decrypt_share(dk, i, &dealing.ciphertexts, None).unwrap())
|
||||
.collect();
|
||||
|
||||
let recovered_secret = combine_shares(shares, &node_indices).unwrap();
|
||||
|
||||
reshared_secrets.push(recovered_secret)
|
||||
}
|
||||
|
||||
let reshared_master = perform_lagrangian_interpolation_at_origin(&[
|
||||
(Scalar::from(node_indices[0]), reshared_secrets[0]),
|
||||
(Scalar::from(join_party_index), reshared_secrets[2]),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
// the master secret and public values didn't change
|
||||
assert_eq!(original_master, reshared_master);
|
||||
assert_eq!(public_original_master, public_reshared_master);
|
||||
|
||||
// but partials did
|
||||
assert_ne!(derived_secrets, reshared_secrets);
|
||||
assert_ne!(recovered_partials, reshared_partials);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// Size of a X25519 private key
|
||||
pub const PRIVATE_KEY_SIZE: usize = 32;
|
||||
@@ -17,31 +19,26 @@ pub const PUBLIC_KEY_SIZE: usize = 32;
|
||||
/// Size of a X25519 shared secret
|
||||
pub const SHARED_SECRET_SIZE: usize = 32;
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Error)]
|
||||
pub enum KeyRecoveryError {
|
||||
InvalidPublicKeyBytes,
|
||||
InvalidPrivateKeyBytes,
|
||||
MalformedString(bs58::decode::Error),
|
||||
}
|
||||
#[error("received public key of invalid size. Got: {received}, expected: {expected}")]
|
||||
InvalidSizePublicKey { received: usize, expected: usize },
|
||||
|
||||
impl From<bs58::decode::Error> for KeyRecoveryError {
|
||||
fn from(err: bs58::decode::Error) -> Self {
|
||||
KeyRecoveryError::MalformedString(err)
|
||||
}
|
||||
}
|
||||
#[error("received private key of invalid size. Got: {received}, expected: {expected}")]
|
||||
InvalidSizePrivateKey { received: usize, expected: usize },
|
||||
|
||||
// required for std::error::Error
|
||||
impl Display for KeyRecoveryError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
KeyRecoveryError::InvalidPrivateKeyBytes => write!(f, "Invalid private key bytes"),
|
||||
KeyRecoveryError::InvalidPublicKeyBytes => write!(f, "Invalid public key bytes"),
|
||||
KeyRecoveryError::MalformedString(err) => write!(f, "malformed string - {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[error("the base58 representation of the public key was malformed - {source}")]
|
||||
MalformedPublicKeyString {
|
||||
#[source]
|
||||
source: bs58::decode::Error,
|
||||
},
|
||||
|
||||
impl std::error::Error for KeyRecoveryError {}
|
||||
#[error("the base58 representation of the private key was malformed - {source}")]
|
||||
MalformedPrivateKeyString {
|
||||
#[source]
|
||||
source: bs58::decode::Error,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct KeyPair {
|
||||
pub(crate) private_key: PrivateKey,
|
||||
@@ -112,7 +109,10 @@ impl PublicKey {
|
||||
|
||||
pub fn from_bytes(b: &[u8]) -> Result<Self, KeyRecoveryError> {
|
||||
if b.len() != PUBLIC_KEY_SIZE {
|
||||
return Err(KeyRecoveryError::InvalidPublicKeyBytes);
|
||||
return Err(KeyRecoveryError::InvalidSizePublicKey {
|
||||
received: b.len(),
|
||||
expected: PUBLIC_KEY_SIZE,
|
||||
});
|
||||
}
|
||||
let mut bytes = [0; PUBLIC_KEY_SIZE];
|
||||
bytes.copy_from_slice(&b[..PUBLIC_KEY_SIZE]);
|
||||
@@ -124,7 +124,9 @@ impl PublicKey {
|
||||
}
|
||||
|
||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, KeyRecoveryError> {
|
||||
let bytes = bs58::decode(val).into_vec()?;
|
||||
let bytes = bs58::decode(val)
|
||||
.into_vec()
|
||||
.map_err(|source| KeyRecoveryError::MalformedPublicKeyString { source })?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
}
|
||||
@@ -188,7 +190,10 @@ impl PrivateKey {
|
||||
|
||||
pub fn from_bytes(b: &[u8]) -> Result<Self, KeyRecoveryError> {
|
||||
if b.len() != PRIVATE_KEY_SIZE {
|
||||
return Err(KeyRecoveryError::InvalidPrivateKeyBytes);
|
||||
return Err(KeyRecoveryError::InvalidSizePrivateKey {
|
||||
received: b.len(),
|
||||
expected: PRIVATE_KEY_SIZE,
|
||||
});
|
||||
}
|
||||
let mut bytes = [0; 32];
|
||||
bytes.copy_from_slice(&b[..PRIVATE_KEY_SIZE]);
|
||||
@@ -200,7 +205,9 @@ impl PrivateKey {
|
||||
}
|
||||
|
||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, KeyRecoveryError> {
|
||||
let bytes = bs58::decode(val).into_vec()?;
|
||||
let bytes = bs58::decode(val)
|
||||
.into_vec()
|
||||
.map_err(|source| KeyRecoveryError::MalformedPrivateKeyString { source })?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@ pub use ed25519_dalek::SignatureError;
|
||||
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::Error as SerdeError;
|
||||
#[cfg(feature = "serde")]
|
||||
@@ -17,35 +18,30 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Ed25519RecoveryError {
|
||||
MalformedBytes(SignatureError),
|
||||
MalformedString(bs58::decode::Error),
|
||||
}
|
||||
#[error(transparent)]
|
||||
MalformedBytes(#[from] SignatureError),
|
||||
|
||||
impl From<SignatureError> for Ed25519RecoveryError {
|
||||
fn from(err: SignatureError) -> Self {
|
||||
Ed25519RecoveryError::MalformedBytes(err)
|
||||
}
|
||||
}
|
||||
#[error("the base58 representation of the public key was malformed - {source}")]
|
||||
MalformedPublicKeyString {
|
||||
#[source]
|
||||
source: bs58::decode::Error,
|
||||
},
|
||||
|
||||
impl From<bs58::decode::Error> for Ed25519RecoveryError {
|
||||
fn from(err: bs58::decode::Error) -> Self {
|
||||
Ed25519RecoveryError::MalformedString(err)
|
||||
}
|
||||
}
|
||||
#[error("the base58 representation of the private key was malformed - {source}")]
|
||||
MalformedPrivateKeyString {
|
||||
#[source]
|
||||
source: bs58::decode::Error,
|
||||
},
|
||||
|
||||
impl fmt::Display for Ed25519RecoveryError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Ed25519RecoveryError::MalformedBytes(err) => write!(f, "malformed bytes - {}", err),
|
||||
Ed25519RecoveryError::MalformedString(err) => write!(f, "malformed string - {}", err),
|
||||
}
|
||||
}
|
||||
#[error("the base58 representation of the signature was malformed - {source}")]
|
||||
MalformedSignatureString {
|
||||
#[source]
|
||||
source: bs58::decode::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for Ed25519RecoveryError {}
|
||||
|
||||
/// Keypair for usage in ed25519 EdDSA.
|
||||
#[derive(Debug)]
|
||||
pub struct KeyPair {
|
||||
@@ -134,7 +130,9 @@ impl PublicKey {
|
||||
}
|
||||
|
||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, Ed25519RecoveryError> {
|
||||
let bytes = bs58::decode(val).into_vec()?;
|
||||
let bytes = bs58::decode(val)
|
||||
.into_vec()
|
||||
.map_err(|source| Ed25519RecoveryError::MalformedPublicKeyString { source })?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
@@ -211,7 +209,9 @@ impl PrivateKey {
|
||||
}
|
||||
|
||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, Ed25519RecoveryError> {
|
||||
let bytes = bs58::decode(val).into_vec()?;
|
||||
let bytes = bs58::decode(val)
|
||||
.into_vec()
|
||||
.map_err(|source| Ed25519RecoveryError::MalformedPrivateKeyString { source })?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
@@ -277,7 +277,9 @@ impl Signature {
|
||||
}
|
||||
|
||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, Ed25519RecoveryError> {
|
||||
let bytes = bs58::decode(val).into_vec()?;
|
||||
let bytes = bs58::decode(val)
|
||||
.into_vec()
|
||||
.map_err(|source| Ed25519RecoveryError::MalformedSignatureString { source })?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
tokio = { version = "1.21.2", features = ["time", "macros", "rt", "net", "io-util"] }
|
||||
tokio-util = { version = "0.7.3", features = ["codec"] }
|
||||
url = "2.2"
|
||||
thiserror = "1.0.37"
|
||||
|
||||
crypto = { path = "../crypto" }
|
||||
nymsphinx-acknowledgements = { path = "../nymsphinx/acknowledgements" }
|
||||
|
||||
@@ -4,63 +4,22 @@
|
||||
use nymsphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
|
||||
use nymsphinx_addressing::nodes::NymNodeRoutingAddressError;
|
||||
use nymsphinx_types::Error as SphinxError;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MixProcessingError {
|
||||
SphinxProcessingError(SphinxError),
|
||||
InvalidHopAddress(NymNodeRoutingAddressError),
|
||||
NoSurbAckInFinalHop,
|
||||
MalformedSurbAck(SurbAckRecoveryError),
|
||||
#[error("failed to process received packet: {0}")]
|
||||
SphinxProcessingError(#[from] SphinxError),
|
||||
|
||||
#[error("the forward hop address was malformed: {0}")]
|
||||
InvalidForwardHopAddress(#[from] NymNodeRoutingAddressError),
|
||||
|
||||
#[error("the final hop did not contain a SURB-Ack")]
|
||||
NoSurbAckInFinalHop,
|
||||
|
||||
#[error("failed to recover the expected SURB-Ack packet: {0}")]
|
||||
MalformedSurbAck(#[from] SurbAckRecoveryError),
|
||||
|
||||
#[error("the received packet was set to use the very old and very much deprecated 'VPN' mode")]
|
||||
ReceivedOldTypeVpnPacket,
|
||||
}
|
||||
|
||||
impl From<SphinxError> for MixProcessingError {
|
||||
// for the time being just have a single error instance for all possible results of SphinxError
|
||||
fn from(err: SphinxError) -> Self {
|
||||
use MixProcessingError::*;
|
||||
|
||||
SphinxProcessingError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NymNodeRoutingAddressError> for MixProcessingError {
|
||||
fn from(err: NymNodeRoutingAddressError) -> Self {
|
||||
use MixProcessingError::*;
|
||||
|
||||
InvalidHopAddress(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SurbAckRecoveryError> for MixProcessingError {
|
||||
fn from(err: SurbAckRecoveryError) -> Self {
|
||||
use MixProcessingError::*;
|
||||
|
||||
MalformedSurbAck(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MixProcessingError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
MixProcessingError::SphinxProcessingError(sphinx_err) => {
|
||||
write!(f, "Sphinx Processing Error - {}", sphinx_err)
|
||||
}
|
||||
MixProcessingError::InvalidHopAddress(address_err) => {
|
||||
write!(f, "Invalid Hop Address - {:?}", address_err)
|
||||
}
|
||||
MixProcessingError::NoSurbAckInFinalHop => {
|
||||
write!(f, "No SURBAck present in the final hop data")
|
||||
}
|
||||
MixProcessingError::MalformedSurbAck(surb_ack_err) => {
|
||||
write!(f, "Malformed SURBAck - {:?}", surb_ack_err)
|
||||
}
|
||||
MixProcessingError::ReceivedOldTypeVpnPacket => {
|
||||
write!(f, "Received an old-type unsafe 'VPN' mode packet")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MixProcessingError {}
|
||||
|
||||
@@ -51,7 +51,7 @@ impl SphinxPacketProcessor {
|
||||
packet: SphinxPacket,
|
||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||
packet.process(&self.sphinx_key).map_err(|err| {
|
||||
debug!("Failed to unwrap Sphinx packet: {:?}", err);
|
||||
debug!("Failed to unwrap Sphinx packet: {err}");
|
||||
MixProcessingError::SphinxProcessingError(err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -53,13 +53,13 @@ impl Display for RttError {
|
||||
write!(f, "The received reply packet had invalid signature")
|
||||
}
|
||||
RttError::UnreachableNode(id, err) => {
|
||||
write!(f, "Could not establish connection to {} - {}", id, err)
|
||||
write!(f, "Could not establish connection to {} - {err}", id)
|
||||
}
|
||||
RttError::UnexpectedConnectionFailureWrite(id, err) => {
|
||||
write!(f, "Failed to write echo packet to {} - {}", id, err)
|
||||
write!(f, "Failed to write echo packet to {} - {err}", id)
|
||||
}
|
||||
RttError::UnexpectedConnectionFailureRead(id, err) => {
|
||||
write!(f, "Failed to read reply packet from {} - {}", id, err)
|
||||
write!(f, "Failed to read reply packet from {} - {err}", id)
|
||||
}
|
||||
RttError::ConnectionReadTimeout(id) => {
|
||||
write!(f, "Timed out while trying to read reply packet from {}", id)
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::fmt::{Display, Formatter};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, io, process};
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_util::codec::{Decoder, Encoder, Framed};
|
||||
@@ -19,14 +19,14 @@ use tokio_util::codec::{Decoder, Encoder, Framed};
|
||||
pub(crate) struct PacketListener {
|
||||
address: SocketAddr,
|
||||
connection_handler: Arc<ConnectionHandler>,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl PacketListener {
|
||||
pub(crate) fn new(
|
||||
address: SocketAddr,
|
||||
identity: Arc<identity::KeyPair>,
|
||||
shutdown: ShutdownListener,
|
||||
shutdown: TaskClient,
|
||||
) -> Self {
|
||||
PacketListener {
|
||||
address,
|
||||
@@ -66,7 +66,7 @@ impl PacketListener {
|
||||
|
||||
tokio::spawn(connection_handler.handle_connection(socket, remote_addr, handler_shutdown_listener));
|
||||
}
|
||||
Err(err) => warn!("Failed to accept incoming connection - {:?}", err),
|
||||
Err(err) => warn!("Failed to accept incoming connection - {err}"),
|
||||
}
|
||||
},
|
||||
_ = shutdown_listener.recv() => {
|
||||
@@ -91,7 +91,7 @@ impl ConnectionHandler {
|
||||
self: Arc<Self>,
|
||||
conn: TcpStream,
|
||||
remote: SocketAddr,
|
||||
mut shutdown_listener: ShutdownListener,
|
||||
mut shutdown_listener: TaskClient,
|
||||
) {
|
||||
debug!("Starting connection handler for {:?}", remote);
|
||||
|
||||
@@ -141,9 +141,9 @@ enum EchoPacketCodecError {
|
||||
impl Display for EchoPacketCodecError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
EchoPacketCodecError::IoError(err) => write!(f, "encountered io error - {}", err),
|
||||
EchoPacketCodecError::IoError(err) => write!(f, "encountered io error - {err}"),
|
||||
EchoPacketCodecError::PacketRecoveryError(err) => {
|
||||
write!(f, "failed to correctly decode an echo packet - {}", err)
|
||||
write!(f, "failed to correctly decode an echo packet - {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use rand::thread_rng;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::sleep;
|
||||
use url::Url;
|
||||
@@ -69,8 +69,8 @@ pub struct Config {
|
||||
/// due to being unable to get the list of nodes.
|
||||
retry_timeout: Duration,
|
||||
|
||||
/// URLs to the validator apis for obtaining network topology.
|
||||
validator_api_urls: Vec<Url>,
|
||||
/// URLs to the nym apis for obtaining network topology.
|
||||
nym_api_urls: Vec<Url>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -132,15 +132,15 @@ impl ConfigBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn validator_api_urls(mut self, validator_api_urls: Vec<Url>) -> Self {
|
||||
self.0.validator_api_urls = validator_api_urls;
|
||||
pub fn nym_api_urls(mut self, nym_api_urls: Vec<Url>) -> Self {
|
||||
self.0.nym_api_urls = nym_api_urls;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Config {
|
||||
// panics here are fine as those are only ever constructed at the initial setup
|
||||
assert!(
|
||||
!self.0.validator_api_urls.is_empty(),
|
||||
!self.0.nym_api_urls.is_empty(),
|
||||
"at least one validator endpoint must be provided",
|
||||
);
|
||||
self.0
|
||||
@@ -159,7 +159,7 @@ impl Default for ConfigBuilder {
|
||||
tested_nodes_batch_size: DEFAULT_BATCH_SIZE,
|
||||
testing_interval: DEFAULT_TESTING_INTERVAL,
|
||||
retry_timeout: DEFAULT_RETRY_TIMEOUT,
|
||||
validator_api_urls: vec![],
|
||||
nym_api_urls: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,7 @@ pub struct VerlocMeasurer {
|
||||
config: Config,
|
||||
packet_sender: Arc<PacketSender>,
|
||||
packet_listener: Arc<PacketListener>,
|
||||
shutdown_listener: ShutdownListener,
|
||||
shutdown_listener: TaskClient,
|
||||
|
||||
currently_used_api: usize,
|
||||
|
||||
@@ -184,9 +184,9 @@ impl VerlocMeasurer {
|
||||
pub fn new(
|
||||
mut config: Config,
|
||||
identity: Arc<identity::KeyPair>,
|
||||
shutdown_listener: ShutdownListener,
|
||||
shutdown_listener: TaskClient,
|
||||
) -> Self {
|
||||
config.validator_api_urls.shuffle(&mut thread_rng());
|
||||
config.nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
VerlocMeasurer {
|
||||
packet_sender: Arc::new(PacketSender::new(
|
||||
@@ -204,24 +204,21 @@ impl VerlocMeasurer {
|
||||
)),
|
||||
shutdown_listener,
|
||||
currently_used_api: 0,
|
||||
validator_client: validator_client::ApiClient::new(
|
||||
config.validator_api_urls[0].clone(),
|
||||
),
|
||||
validator_client: validator_client::ApiClient::new(config.nym_api_urls[0].clone()),
|
||||
config,
|
||||
results: AtomicVerlocResult::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_validator_api(&mut self) {
|
||||
if self.config.validator_api_urls.len() == 1 {
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.config.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single validator API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api =
|
||||
(self.currently_used_api + 1) % self.config.validator_api_urls.len();
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.config.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_validator_api(self.config.validator_api_urls[self.currently_used_api].clone())
|
||||
.change_nym_api(self.config.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
pub fn get_verloc_results_pointer(&self) -> AtomicVerlocResult {
|
||||
@@ -308,7 +305,7 @@ impl VerlocMeasurer {
|
||||
"failed to obtain list of mixnodes from the validator - {}. Going to attempt to use another validator API in the next run",
|
||||
err
|
||||
);
|
||||
self.use_next_validator_api();
|
||||
self.use_next_nym_api();
|
||||
sleep(self.config.retry_timeout).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{fmt, io};
|
||||
use task::ShutdownListener;
|
||||
use task::TaskClient;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::time::sleep;
|
||||
@@ -45,7 +45,7 @@ pub(crate) struct PacketSender {
|
||||
packet_timeout: Duration,
|
||||
connection_timeout: Duration,
|
||||
delay_between_packets: Duration,
|
||||
shutdown_listener: ShutdownListener,
|
||||
shutdown_listener: TaskClient,
|
||||
}
|
||||
|
||||
impl PacketSender {
|
||||
@@ -55,7 +55,7 @@ impl PacketSender {
|
||||
packet_timeout: Duration,
|
||||
connection_timeout: Duration,
|
||||
delay_between_packets: Duration,
|
||||
shutdown_listener: ShutdownListener,
|
||||
shutdown_listener: TaskClient,
|
||||
) -> Self {
|
||||
PacketSender {
|
||||
identity,
|
||||
|
||||
@@ -355,14 +355,14 @@ pub const DEFAULT_WEBSOCKET_LISTENING_PORT: u16 = 1977;
|
||||
// 'SOCKS5' CLIENT
|
||||
pub const DEFAULT_SOCKS5_LISTENING_PORT: u16 = 1080;
|
||||
|
||||
// VALIDATOR-API
|
||||
pub const DEFAULT_VALIDATOR_API_PORT: u16 = 8080;
|
||||
// NYM-API
|
||||
pub const DEFAULT_NYM_API_PORT: u16 = 8080;
|
||||
|
||||
pub const VALIDATOR_API_VERSION: &str = "v1";
|
||||
pub const NYM_API_VERSION: &str = "v1";
|
||||
|
||||
// REWARDING
|
||||
|
||||
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate interval costs to Nyms. We'll also assume a cost of 40$ per interval(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
|
||||
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have reliable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate interval costs to Nyms. We'll also assume a cost of 40$ per interval(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
|
||||
// pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 40_000_000; // 40$/(30 days) at 1 Nym == 1$
|
||||
// pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 55_556; // 40$/1hr at 1 Nym == 1$
|
||||
// pub const DEFAULT_OPERATOR_INTERVAL_COST: u64 = 9259; // 40$/1hr/6 at 1 Nym == 1$
|
||||
|
||||
@@ -8,6 +8,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
thiserror = "1.0.37"
|
||||
|
||||
crypto = { path = "../../crypto", features = ["symmetric", "rand"] }
|
||||
nymsphinx-addressing = { path = "../addressing" }
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
use crate::identifier::prepare_identifier;
|
||||
use crate::AckKey;
|
||||
use nymsphinx_addressing::clients::Recipient;
|
||||
use nymsphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
||||
use nymsphinx_addressing::nodes::{
|
||||
NymNodeRoutingAddress, NymNodeRoutingAddressError, MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
};
|
||||
use nymsphinx_params::packet_sizes::PacketSize;
|
||||
use nymsphinx_params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nymsphinx_types::builder::SphinxPacketBuilder;
|
||||
use nymsphinx_types::Error as SphinxError;
|
||||
use nymsphinx_types::{
|
||||
delays::{self, Delay},
|
||||
SphinxPacket,
|
||||
@@ -15,6 +18,7 @@ use nymsphinx_types::{
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
use std::time;
|
||||
use thiserror::Error;
|
||||
use topology::{NymTopology, NymTopologyError};
|
||||
|
||||
pub struct SurbAck {
|
||||
@@ -23,11 +27,16 @@ pub struct SurbAck {
|
||||
expected_total_delay: Delay,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SurbAckRecoveryError {
|
||||
InvalidPacketSize,
|
||||
InvalidAddress,
|
||||
InvalidSphinxPacket,
|
||||
#[error("received an invalid number of bytes to deserialize the SURB-Ack. Got {received}, expected {expected}")]
|
||||
InvalidPacketSize { received: usize, expected: usize },
|
||||
|
||||
#[error("could not extract first hop address information - {0}")]
|
||||
InvalidAddress(#[from] NymNodeRoutingAddressError),
|
||||
|
||||
#[error("the contained sphinx packet was not correctly formed - {0}")]
|
||||
InvalidSphinxPacket(#[from] SphinxError),
|
||||
}
|
||||
|
||||
impl SurbAck {
|
||||
@@ -92,20 +101,17 @@ impl SurbAck {
|
||||
b: &[u8],
|
||||
) -> Result<(NymNodeRoutingAddress, SphinxPacket), SurbAckRecoveryError> {
|
||||
if b.len() != Self::len() {
|
||||
Err(SurbAckRecoveryError::InvalidPacketSize)
|
||||
Err(SurbAckRecoveryError::InvalidPacketSize {
|
||||
received: b.len(),
|
||||
expected: Self::len(),
|
||||
})
|
||||
} else {
|
||||
let address = match NymNodeRoutingAddress::try_from_bytes(b) {
|
||||
Ok(address) => address,
|
||||
Err(_) => return Err(SurbAckRecoveryError::InvalidAddress),
|
||||
};
|
||||
let address = NymNodeRoutingAddress::try_from_bytes(b)?;
|
||||
|
||||
// TODO: this will be variable once/if we decide to introduce optimization described
|
||||
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
||||
let address_offset = MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
let packet = match SphinxPacket::from_bytes(&b[address_offset..]) {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => return Err(SurbAckRecoveryError::InvalidSphinxPacket),
|
||||
};
|
||||
let packet = SphinxPacket::from_bytes(&b[address_offset..])?;
|
||||
|
||||
Ok((address, packet))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
bytes = "1.0"
|
||||
tokio-util = { version = "0.7.3", features = ["codec"] }
|
||||
thiserror = "1.0.37"
|
||||
|
||||
nymsphinx-types = { path = "../types" }
|
||||
nymsphinx-params = { path = "../params" }
|
||||
|
||||
@@ -1,57 +1,48 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::packet::{FramedSphinxPacket, Header};
|
||||
use bytes::{Buf, BufMut, BytesMut};
|
||||
use nymsphinx_params::packet_modes::InvalidPacketMode;
|
||||
use nymsphinx_params::packet_sizes::{InvalidPacketSize, PacketSize};
|
||||
use nymsphinx_types::Error as SphinxError;
|
||||
use nymsphinx_types::SphinxPacket;
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
use tokio_util::codec::{Decoder, Encoder};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SphinxCodecError {
|
||||
InvalidPacketSize,
|
||||
InvalidPacketMode,
|
||||
MalformedSphinxPacket,
|
||||
IoError(io::Error),
|
||||
}
|
||||
#[error("the packet size information was malformed - {0}")]
|
||||
InvalidPacketSize(#[from] InvalidPacketSize),
|
||||
|
||||
impl From<io::Error> for SphinxCodecError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
SphinxCodecError::IoError(err)
|
||||
}
|
||||
#[error("the packet mode information was malformed - {0}")]
|
||||
InvalidPacketMode(#[from] InvalidPacketMode),
|
||||
|
||||
#[error("the actual sphinx packet was malformed - {0}")]
|
||||
MalformedSphinxPacket(#[from] SphinxError),
|
||||
|
||||
#[error("encountered an IO error - {0}")]
|
||||
IoError(#[from] io::Error),
|
||||
}
|
||||
|
||||
impl From<SphinxCodecError> for io::Error {
|
||||
fn from(err: SphinxCodecError) -> Self {
|
||||
match err {
|
||||
SphinxCodecError::InvalidPacketSize => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "invalid packet size")
|
||||
SphinxCodecError::InvalidPacketSize(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||
}
|
||||
SphinxCodecError::InvalidPacketMode => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "invalid packet mode")
|
||||
SphinxCodecError::InvalidPacketMode(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||
}
|
||||
SphinxCodecError::MalformedSphinxPacket => {
|
||||
io::Error::new(io::ErrorKind::InvalidData, "malformed packet")
|
||||
SphinxCodecError::MalformedSphinxPacket(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidData, source)
|
||||
}
|
||||
SphinxCodecError::IoError(err) => err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidPacketSize> for SphinxCodecError {
|
||||
fn from(_: InvalidPacketSize) -> Self {
|
||||
SphinxCodecError::InvalidPacketSize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidPacketMode> for SphinxCodecError {
|
||||
fn from(_: InvalidPacketMode) -> Self {
|
||||
SphinxCodecError::InvalidPacketMode
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: in the future it could be extended to have state containing symmetric encryption key
|
||||
// so that all data could be encrypted easily (alternatively we could just slap TLS)
|
||||
pub struct SphinxCodec;
|
||||
@@ -97,17 +88,11 @@ impl Decoder for SphinxCodec {
|
||||
// advance buffer past the header - at this point we have enough bytes
|
||||
src.advance(header.size());
|
||||
let sphinx_packet_bytes = src.split_to(sphinx_packet_size);
|
||||
let sphinx_packet = match SphinxPacket::from_bytes(&sphinx_packet_bytes) {
|
||||
Ok(sphinx_packet) => sphinx_packet,
|
||||
// here it could be debatable whether stream is corrupt or not,
|
||||
// but let's go with the safer approach and assume it is.
|
||||
Err(_) => return Err(SphinxCodecError::MalformedSphinxPacket),
|
||||
};
|
||||
|
||||
let nymsphinx_packet = FramedSphinxPacket {
|
||||
header,
|
||||
packet: sphinx_packet,
|
||||
};
|
||||
// here it could be debatable whether stream is corrupt or not,
|
||||
// but let's go with the safer approach and assume it is.
|
||||
let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
||||
let nymsphinx_packet = FramedSphinxPacket { header, packet };
|
||||
|
||||
// As per docs:
|
||||
// Before returning from the function, implementations should ensure that the buffer
|
||||
|
||||
@@ -7,5 +7,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.37"
|
||||
|
||||
crypto = { path = "../../crypto", features = ["hashing", "symmetric"] }
|
||||
nymsphinx-types = { path = "../types" }
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InvalidPacketMode;
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{received} is not a valid packet mode tag")]
|
||||
pub struct InvalidPacketMode {
|
||||
received: u8,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -31,11 +35,11 @@ impl PacketMode {
|
||||
impl TryFrom<u8> for PacketMode {
|
||||
type Error = InvalidPacketMode;
|
||||
|
||||
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
_ if value == (PacketMode::Mix as u8) => Ok(Self::Mix),
|
||||
_ if value == (PacketMode::Vpn as u8) => Ok(Self::Vpn),
|
||||
_ => Err(InvalidPacketMode),
|
||||
v => Err(InvalidPacketMode { received: v }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use nymsphinx_types::header::HEADER_SIZE;
|
||||
use nymsphinx_types::PAYLOAD_OVERHEAD_SIZE;
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
// it's up to the smart people to figure those values out : )
|
||||
const REGULAR_PACKET_SIZE: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 2 * 1024;
|
||||
@@ -20,11 +21,17 @@ const EXTENDED_PACKET_SIZE_8: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 8 *
|
||||
const EXTENDED_PACKET_SIZE_16: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 16 * 1024;
|
||||
const EXTENDED_PACKET_SIZE_32: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 32 * 1024;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InvalidPacketSize;
|
||||
#[derive(Debug, Error)]
|
||||
pub enum InvalidPacketSize {
|
||||
#[error("{received} is not a valid packet size tag")]
|
||||
UnknownPacketTag { received: u8 },
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InvalidExtendedPacketSize;
|
||||
#[error("{received} is not a valid extended packet size variant")]
|
||||
UnknownExtendedPacketVariant { received: String },
|
||||
|
||||
#[error("{received} does not correspond with any known packet size")]
|
||||
UnknownPacketSize { received: usize },
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -55,7 +62,9 @@ impl FromStr for PacketSize {
|
||||
"extended8" => Ok(Self::ExtendedPacket8),
|
||||
"extended16" => Ok(Self::ExtendedPacket16),
|
||||
"extended32" => Ok(Self::ExtendedPacket32),
|
||||
_ => Err(InvalidPacketSize),
|
||||
s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
|
||||
received: s.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,14 +72,14 @@ impl FromStr for PacketSize {
|
||||
impl TryFrom<u8> for PacketSize {
|
||||
type Error = InvalidPacketSize;
|
||||
|
||||
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
_ if value == (PacketSize::RegularPacket as u8) => Ok(Self::RegularPacket),
|
||||
_ if value == (PacketSize::AckPacket as u8) => Ok(Self::AckPacket),
|
||||
_ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
|
||||
_ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
|
||||
_ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
|
||||
_ => Err(InvalidPacketSize),
|
||||
v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +103,7 @@ impl PacketSize {
|
||||
self.size() - HEADER_SIZE
|
||||
}
|
||||
|
||||
pub fn get_type(size: usize) -> std::result::Result<Self, InvalidPacketSize> {
|
||||
pub fn get_type(size: usize) -> Result<Self, InvalidPacketSize> {
|
||||
if PacketSize::RegularPacket.size() == size {
|
||||
Ok(PacketSize::RegularPacket)
|
||||
} else if PacketSize::AckPacket.size() == size {
|
||||
@@ -106,7 +115,7 @@ impl PacketSize {
|
||||
} else if PacketSize::ExtendedPacket32.size() == size {
|
||||
Ok(PacketSize::ExtendedPacket32)
|
||||
} else {
|
||||
Err(InvalidPacketSize)
|
||||
Err(InvalidPacketSize::UnknownPacketSize { received: size })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user