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("invalid data: {0}")]
48 InvalidData(String),
49
50 #[error("serialization error: {0}")]
52 Serialization(String),
53
54 #[error("crypto error: {0}")]
56 Crypto(String),
57
58 #[error("I/O error: {0}")]
60 Io(#[from] std::io::Error),
61
62 #[error("configuration error: {0}")]
64 Config(String),
65
66 #[error("timeout: {0}")]
68 Timeout(String),
69
70 #[error("insufficient peers: {0}")]
72 InsufficientPeers(String),
73
74 #[error("signature verification failed: {0}")]
76 SignatureVerification(String),
77
78 #[error("encryption error: {0}")]
80 Encryption(String),
81
82 #[error("operation cancelled: {0}")]
88 Cancelled(String),
89
90 #[error("already stored on network")]
92 AlreadyStored,
93
94 #[error("bad quote binding from peer {peer_id}: {detail}")]
98 BadQuoteBinding {
99 peer_id: String,
101 detail: String,
103 },
104
105 #[error("insufficient disk space: {0}")]
107 InsufficientDiskSpace(String),
108
109 #[error("cost estimation inconclusive: {0}")]
116 CostEstimationInconclusive(String),
117
118 #[error(
122 "partial upload: {stored_count}/{total_chunks} stored, {failed_count} failed: {reason}"
123 )]
124 PartialUpload {
125 stored: Vec<[u8; 32]>,
127 stored_count: usize,
129 failed: Vec<([u8; 32], String)>,
131 failed_count: usize,
133 total_chunks: usize,
135 spend: Box<PartialUploadSpend>,
139 reason: String,
141 },
142}
143
144#[derive(Debug, Clone, PartialEq, Eq)]
151pub struct PartialUploadSpend {
152 pub storage_cost_atto: String,
154 pub gas_cost_wei: u128,
156}
157
158#[cfg(feature = "devnet")]
162impl From<ant_node::Error> for Error {
163 fn from(e: ant_node::Error) -> Self {
164 Self::Network(e.to_string())
165 }
166}
167
168#[cfg(test)]
169#[allow(clippy::unwrap_used, clippy::expect_used)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn test_display_network() {
175 let err = Error::Network("connection refused".to_string());
176 assert_eq!(err.to_string(), "network error: connection refused");
177 }
178
179 #[test]
180 fn test_display_storage() {
181 let err = Error::Storage("disk full".to_string());
182 assert_eq!(err.to_string(), "storage error: disk full");
183 }
184
185 #[test]
186 fn test_display_payment() {
187 let err = Error::Payment("insufficient funds".to_string());
188 assert_eq!(err.to_string(), "payment error: insufficient funds");
189 }
190
191 #[test]
192 fn test_display_protocol() {
193 let err = Error::Protocol("invalid message".to_string());
194 assert_eq!(err.to_string(), "protocol error: invalid message");
195 }
196
197 #[test]
198 fn test_display_invalid_data() {
199 let err = Error::InvalidData("bad hash".to_string());
200 assert_eq!(err.to_string(), "invalid data: bad hash");
201 }
202
203 #[test]
204 fn test_display_serialization() {
205 let err = Error::Serialization("decode failed".to_string());
206 assert_eq!(err.to_string(), "serialization error: decode failed");
207 }
208
209 #[test]
210 fn test_display_crypto() {
211 let err = Error::Crypto("key mismatch".to_string());
212 assert_eq!(err.to_string(), "crypto error: key mismatch");
213 }
214
215 #[test]
216 fn test_display_io() {
217 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
218 let err = Error::Io(io_err);
219 assert_eq!(err.to_string(), "I/O error: file missing");
220 }
221
222 #[test]
223 fn test_display_config() {
224 let err = Error::Config("bad value".to_string());
225 assert_eq!(err.to_string(), "configuration error: bad value");
226 }
227
228 #[test]
229 fn test_display_timeout() {
230 let err = Error::Timeout("30s elapsed".to_string());
231 assert_eq!(err.to_string(), "timeout: 30s elapsed");
232 }
233
234 #[test]
235 fn test_display_insufficient_peers() {
236 let err = Error::InsufficientPeers("need 5, got 2".to_string());
237 assert_eq!(err.to_string(), "insufficient peers: need 5, got 2");
238 }
239
240 #[test]
241 fn test_display_signature_verification() {
242 let err = Error::SignatureVerification("invalid sig".to_string());
243 assert_eq!(
244 err.to_string(),
245 "signature verification failed: invalid sig"
246 );
247 }
248
249 #[test]
250 fn test_display_encryption() {
251 let err = Error::Encryption("decrypt failed".to_string());
252 assert_eq!(err.to_string(), "encryption error: decrypt failed");
253 }
254
255 #[test]
256 fn test_display_cancelled() {
257 let err = Error::Cancelled("download stream receiver dropped".to_string());
258 assert_eq!(
259 err.to_string(),
260 "operation cancelled: download stream receiver dropped"
261 );
262 }
263
264 #[test]
265 fn test_display_insufficient_disk_space() {
266 let err = Error::InsufficientDiskSpace("need 100 MB but only 10 MB available".to_string());
267 assert_eq!(
268 err.to_string(),
269 "insufficient disk space: need 100 MB but only 10 MB available"
270 );
271 }
272
273 #[test]
274 fn test_display_cost_estimation_inconclusive() {
275 let err = Error::CostEstimationInconclusive(
276 "sampled 5 addresses, all already stored".to_string(),
277 );
278 assert_eq!(
279 err.to_string(),
280 "cost estimation inconclusive: sampled 5 addresses, all already stored"
281 );
282 }
283
284 #[test]
285 fn test_from_io_error() {
286 let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "access denied");
287 let err: Error = io_err.into();
288 assert!(matches!(err, Error::Io(_)));
289 }
290}