nym_client_core/
error.rs

1// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::client::mix_traffic::transceiver::ErasedGatewayError;
5use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
6use nym_gateway_client::error::GatewayClientError;
7use nym_task::RegistryAccessError;
8use nym_topology::node::RoutingNodeError;
9use nym_topology::{NodeId, NymTopologyError};
10use nym_validator_client::nym_api::error::NymAPIError;
11use nym_validator_client::nyxd::error::NyxdError;
12use nym_validator_client::ValidatorClientError;
13use rand::distributions::WeightedError;
14use std::error::Error;
15use std::path::PathBuf;
16
17#[derive(thiserror::Error, Debug)]
18pub enum ClientCoreError {
19    #[error("could not perform the state migration: {0}")]
20    UnsupportedMigration(String),
21
22    #[error("I/O error: {0}")]
23    IoError(#[from] std::io::Error),
24
25    #[error("gateway client error ({gateway_id}): {source}")]
26    GatewayClientError {
27        gateway_id: String,
28        source: Box<GatewayClientError>,
29    },
30
31    #[error("custom gateway client error: {source}")]
32    ErasedGatewayClientError {
33        #[from]
34        source: ErasedGatewayError,
35    },
36
37    #[error("ed25519 error: {0}")]
38    Ed25519RecoveryError(#[from] Ed25519RecoveryError),
39
40    #[error("validator client error: {0}")]
41    ValidatorClientError(#[from] ValidatorClientError),
42
43    #[error("no gateway with id: {0}")]
44    NoGatewayWithId(String),
45
46    #[error("Invalid URL: {0}")]
47    InvalidUrl(String),
48
49    #[error("node doesn't advertise ip addresses : {0}")]
50    MissingIpAddress(String),
51
52    #[cfg(not(target_arch = "wasm32"))]
53    #[error("resolution failed: {0}")]
54    ResolutionFailed(#[from] nym_http_api_client::ResolveError),
55
56    #[error("no gateways on network")]
57    NoGatewaysOnNetwork,
58
59    #[error("there are no more new gateways on the network - it seems this client has already registered with all nodes it could have")]
60    NoNewGatewaysAvailable,
61
62    #[error("list of nym apis is empty")]
63    ListOfNymApisIsEmpty,
64
65    #[error("failed to resolve a query to nym API: {source}")]
66    NymApiQueryFailure { source: Box<NymAPIError> },
67
68    #[error(
69        "the current network topology seem to be insufficient to route any packets through:\n\t{0}"
70    )]
71    InsufficientNetworkTopology(#[from] NymTopologyError),
72
73    #[error("experienced a failure with our reply surb persistent storage: {source}")]
74    SurbStorageError {
75        source: Box<dyn Error + Send + Sync>,
76    },
77
78    #[error("experienced a failure with our cryptographic keys persistent storage: {source}")]
79    KeyStoreError {
80        source: Box<dyn Error + Send + Sync>,
81    },
82
83    #[error("experienced a failure with our gateways details storage: {source}")]
84    GatewaysDetailsStoreError {
85        source: Box<dyn Error + Send + Sync>,
86    },
87
88    #[error("experienced a failure with our credentials storage: {source}")]
89    CredentialStoreError {
90        source: Box<dyn Error + Send + Sync>,
91    },
92
93    #[error("the provided ticket type is invalid")]
94    UnknownTicketType,
95
96    #[error("the gateway id is invalid - {0}")]
97    UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
98
99    #[error("the node is malformed: {source}")]
100    MalformedGateway {
101        #[from]
102        source: Box<RoutingNodeError>,
103    },
104
105    #[error("failed to establish connection to gateway: {source}")]
106    GatewayConnectionFailure { source: Box<tungstenite::Error> },
107
108    #[cfg(target_arch = "wasm32")]
109    #[error("failed to establish gateway connection (wasm)")]
110    GatewayJsConnectionFailure,
111
112    #[error("gateway connection was abruptly closed")]
113    GatewayConnectionAbruptlyClosed,
114
115    #[error("timed out while trying to establish gateway connection")]
116    GatewayConnectionTimeout,
117
118    #[error("failed to forward mix messages to gateway")]
119    GatewayFailedToForwardMessages,
120
121    #[error("no ping measurements for the gateway ({identity}) performed")]
122    NoGatewayMeasurements { identity: String },
123
124    #[error("failed to register receiver for reconstructed mixnet messages")]
125    FailedToRegisterReceiver,
126
127    #[error("unexpected exit")]
128    UnexpectedExit,
129
130    #[error("this operation would have resulted in the gateway {gateway_id:?} key being overwritten without permission")]
131    ForbiddenGatewayKeyOverwrite { gateway_id: String },
132
133    #[error(
134        "this operation would have resulted in clients keys being overwritten without permission"
135    )]
136    ForbiddenKeyOverwrite,
137
138    #[error("the client doesn't have any gateway set as active")]
139    NoActiveGatewaySet,
140
141    #[error("gateway details for gateway {gateway_id:?} are unavailable")]
142    UnavailableGatewayDetails {
143        gateway_id: String,
144        #[source]
145        source: Box<dyn Error + Send + Sync>,
146    },
147
148    #[error("gateway shared key is unavailable whilst we have full node information")]
149    UnavailableSharedKey,
150
151    #[error("attempted to obtain fresh gateway details whilst already knowing about one")]
152    UnexpectedGatewayDetails,
153
154    #[error("the provided gateway details (for gateway {gateway_id}) do not correspond to the shared keys")]
155    MismatchedGatewayDetails { gateway_id: String },
156
157    #[error("unable to upgrade config file from `{current_version}`")]
158    ConfigFileUpgradeFailure { current_version: String },
159
160    #[error("unable to upgrade config file to `{new_version}`")]
161    UnableToUpgradeConfigFile { new_version: String },
162
163    #[error("failed to upgrade config file: {message}")]
164    UpgradeFailure { message: String },
165
166    #[error("the provided gateway details don't much the stored data")]
167    MismatchedStoredGatewayDetails,
168
169    #[error("custom selection of gateway was expected")]
170    CustomGatewaySelectionExpected,
171
172    #[error("custom selection of gateway was unexpected")]
173    UnexpectedCustomGatewaySelection,
174
175    #[error("the persisted gateway details were set for a custom setup")]
176    UnexpectedPersistedCustomGatewayDetails,
177
178    #[error("this client has performed gateway initialisation in another session")]
179    NoInitClientPresent,
180
181    #[error("there are no gateways supporting the wss protocol available")]
182    NoWssGateways,
183
184    #[error("the specified gateway '{gateway}' does not support the wss protocol")]
185    UnsupportedWssProtocol { gateway: String },
186
187    #[error("node {id} ({identity}) does not support mixnet entry mode")]
188    UnsupportedEntry { id: NodeId, identity: String },
189
190    #[error(
191    "failed to load custom topology using path '{}'. detailed message: {source}", file_path.display()
192    )]
193    CustomTopologyLoadFailure {
194        file_path: PathBuf,
195        #[source]
196        source: std::io::Error,
197    },
198
199    #[error(
200    "failed to save config file for client-{typ} id {id} using path '{}'. detailed message: {source}", path.display()
201    )]
202    ConfigSaveFailure {
203        typ: String,
204        id: String,
205        path: PathBuf,
206        #[source]
207        source: std::io::Error,
208    },
209
210    #[error("the provided gateway identity {gateway_id} is malformed: {source}")]
211    MalformedGatewayIdentity {
212        gateway_id: String,
213
214        #[source]
215        source: Ed25519RecoveryError,
216    },
217
218    #[error(
219        "the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}"
220    )]
221    MalformedListener {
222        gateway_id: String,
223
224        raw_listener: String,
225
226        #[source]
227        source: url::ParseError,
228    },
229
230    #[error("this client (id: '{client_id}') has already been initialised before. If you want to add additional gateway, use `add-gateway` command")]
231    AlreadyInitialised { client_id: String },
232
233    #[error("this client has already registered with gateway {gateway_id}")]
234    AlreadyRegistered { gateway_id: String },
235
236    #[error(
237        "fresh registration with gateway {gateway_id} somehow requires an additional key upgrade!"
238    )]
239    UnexpectedKeyUpgrade { gateway_id: String },
240
241    #[error("failed to derive keys from master key")]
242    HkdfDerivationError,
243
244    #[error("missing url for constructing RPC client")]
245    RpcClientMissingUrl,
246
247    #[error("provided nym network details were malformed: {source}")]
248    InvalidNetworkDetails { source: NyxdError },
249
250    #[error("failed to construct RPC client: {source}")]
251    RpcClientCreationFailure { source: NyxdError },
252
253    #[error("failed to select valid gateway due to incomputable latency")]
254    GatewaySelectionFailure { source: WeightedError },
255
256    #[error("Could not access task registry, {0}")]
257    RegistryAccess(#[from] RegistryAccessError),
258}
259
260impl From<tungstenite::Error> for ClientCoreError {
261    fn from(err: tungstenite::Error) -> ClientCoreError {
262        ClientCoreError::GatewayConnectionFailure {
263            source: Box::new(err),
264        }
265    }
266}
267
268impl From<NymAPIError> for ClientCoreError {
269    fn from(err: NymAPIError) -> ClientCoreError {
270        ClientCoreError::NymApiQueryFailure {
271            source: Box::new(err),
272        }
273    }
274}
275
276/// Set of messages that the client can send to listeners via the task manager
277#[derive(Debug)]
278pub enum ClientCoreStatusMessage {
279    GatewayIsSlow,
280    GatewayIsVerySlow,
281}
282
283impl std::fmt::Display for ClientCoreStatusMessage {
284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285        match self {
286            ClientCoreStatusMessage::GatewayIsSlow => write!(
287                f,
288                "The connected gateway is slow, or the connection to it is slow"
289            ),
290            ClientCoreStatusMessage::GatewayIsVerySlow => write!(
291                f,
292                "The connected gateway is very slow, or the connection to it is very slow"
293            ),
294        }
295    }
296}
297
298impl nym_task::TaskStatusEvent for ClientCoreStatusMessage {
299    fn as_any(&self) -> &dyn std::any::Any {
300        self
301    }
302}