1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Error, Debug)]
10pub enum Error {
11 #[error("network error: {0}")]
13 Network(String),
14
15 #[error("storage error: {0}")]
17 Storage(String),
18
19 #[error("payment error: {0}")]
21 Payment(String),
22
23 #[error("protocol error: {0}")]
25 Protocol(String),
26
27 #[error("remote PUT rejected for {address}: {source}")]
39 RemotePut {
40 address: String,
42 source: ant_protocol::ProtocolError,
44 },
45
46 #[error("close-group PUT shortfall (dial churn): {0}")]
61 CloseGroupShortfall(String),
62
63 #[error("invalid data: {0}")]
65 InvalidData(String),
66
67 #[error("serialization error: {0}")]
69 Serialization(String),
70
71 #[error("crypto error: {0}")]
73 Crypto(String),
74
75 #[error("I/O error: {0}")]
77 Io(#[from] std::io::Error),
78
79 #[error("configuration error: {0}")]
81 Config(String),
82
83 #[error("timeout: {0}")]
85 Timeout(String),
86
87 #[error("insufficient peers: {0}")]
89 InsufficientPeers(String),
90
91 #[error("signature verification failed: {0}")]
93 SignatureVerification(String),
94
95 #[error("encryption error: {0}")]
97 Encryption(String),
98
99 #[error("operation cancelled: {0}")]
105 Cancelled(String),
106
107 #[error("already stored on network")]
109 AlreadyStored,
110
111 #[error("bad quote binding from peer {peer_id}: {detail}")]
115 BadQuoteBinding {
116 peer_id: String,
118 detail: String,
120 },
121
122 #[error("insufficient disk space: {0}")]
124 InsufficientDiskSpace(String),
125
126 #[error("cost estimation inconclusive: {0}")]
133 CostEstimationInconclusive(String),
134
135 #[error(
139 "partial upload: {stored_count}/{total_chunks} stored, {failed_count} failed: {reason}"
140 )]
141 PartialUpload {
142 stored: Vec<[u8; 32]>,
144 stored_count: usize,
146 failed: Vec<([u8; 32], String)>,
148 failed_count: usize,
150 total_chunks: usize,
152 spend: Box<PartialUploadSpend>,
156 reason: String,
158 },
159}
160
161#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct PartialUploadSpend {
169 pub storage_cost_atto: String,
171 pub gas_cost_wei: u128,
173}
174
175#[cfg(feature = "devnet")]
179impl From<ant_node::Error> for Error {
180 fn from(e: ant_node::Error) -> Self {
181 Self::Network(e.to_string())
182 }
183}
184
185#[cfg(test)]
186#[allow(clippy::unwrap_used, clippy::expect_used)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_display_network() {
192 let err = Error::Network("connection refused".to_string());
193 assert_eq!(err.to_string(), "network error: connection refused");
194 }
195
196 #[test]
197 fn test_display_storage() {
198 let err = Error::Storage("disk full".to_string());
199 assert_eq!(err.to_string(), "storage error: disk full");
200 }
201
202 #[test]
203 fn test_display_payment() {
204 let err = Error::Payment("insufficient funds".to_string());
205 assert_eq!(err.to_string(), "payment error: insufficient funds");
206 }
207
208 #[test]
209 fn test_display_protocol() {
210 let err = Error::Protocol("invalid message".to_string());
211 assert_eq!(err.to_string(), "protocol error: invalid message");
212 }
213
214 #[test]
215 fn test_display_invalid_data() {
216 let err = Error::InvalidData("bad hash".to_string());
217 assert_eq!(err.to_string(), "invalid data: bad hash");
218 }
219
220 #[test]
221 fn test_display_serialization() {
222 let err = Error::Serialization("decode failed".to_string());
223 assert_eq!(err.to_string(), "serialization error: decode failed");
224 }
225
226 #[test]
227 fn test_display_crypto() {
228 let err = Error::Crypto("key mismatch".to_string());
229 assert_eq!(err.to_string(), "crypto error: key mismatch");
230 }
231
232 #[test]
233 fn test_display_io() {
234 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
235 let err = Error::Io(io_err);
236 assert_eq!(err.to_string(), "I/O error: file missing");
237 }
238
239 #[test]
240 fn test_display_config() {
241 let err = Error::Config("bad value".to_string());
242 assert_eq!(err.to_string(), "configuration error: bad value");
243 }
244
245 #[test]
246 fn test_display_timeout() {
247 let err = Error::Timeout("30s elapsed".to_string());
248 assert_eq!(err.to_string(), "timeout: 30s elapsed");
249 }
250
251 #[test]
252 fn test_display_insufficient_peers() {
253 let err = Error::InsufficientPeers("need 5, got 2".to_string());
254 assert_eq!(err.to_string(), "insufficient peers: need 5, got 2");
255 }
256
257 #[test]
258 fn test_display_close_group_shortfall() {
259 let err = Error::CloseGroupShortfall("Stored on 3 peers, need 4".to_string());
260 assert_eq!(
261 err.to_string(),
262 "close-group PUT shortfall (dial churn): Stored on 3 peers, need 4"
263 );
264 }
265
266 #[test]
267 fn test_display_signature_verification() {
268 let err = Error::SignatureVerification("invalid sig".to_string());
269 assert_eq!(
270 err.to_string(),
271 "signature verification failed: invalid sig"
272 );
273 }
274
275 #[test]
276 fn test_display_encryption() {
277 let err = Error::Encryption("decrypt failed".to_string());
278 assert_eq!(err.to_string(), "encryption error: decrypt failed");
279 }
280
281 #[test]
282 fn test_display_cancelled() {
283 let err = Error::Cancelled("download stream receiver dropped".to_string());
284 assert_eq!(
285 err.to_string(),
286 "operation cancelled: download stream receiver dropped"
287 );
288 }
289
290 #[test]
291 fn test_display_insufficient_disk_space() {
292 let err = Error::InsufficientDiskSpace("need 100 MB but only 10 MB available".to_string());
293 assert_eq!(
294 err.to_string(),
295 "insufficient disk space: need 100 MB but only 10 MB available"
296 );
297 }
298
299 #[test]
300 fn test_display_cost_estimation_inconclusive() {
301 let err = Error::CostEstimationInconclusive(
302 "sampled 5 addresses, all already stored".to_string(),
303 );
304 assert_eq!(
305 err.to_string(),
306 "cost estimation inconclusive: sampled 5 addresses, all already stored"
307 );
308 }
309
310 #[test]
311 fn test_from_io_error() {
312 let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "access denied");
313 let err: Error = io_err.into();
314 assert!(matches!(err, Error::Io(_)));
315 }
316}