1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[repr(u16)]
11pub enum ErrorCode {
12 Ok = 0x0000,
15 OkPartial = 0x0001,
17
18 InvalidMagic = 0x0100,
21 InvalidVersion = 0x0101,
23 InvalidChecksum = 0x0102,
25 InvalidSignature = 0x0103,
27 TruncatedSegment = 0x0104,
29 InvalidManifest = 0x0105,
31 ManifestNotFound = 0x0106,
33 UnknownSegmentType = 0x0107,
35 AlignmentError = 0x0108,
37
38 DimensionMismatch = 0x0200,
41 EmptyIndex = 0x0201,
43 MetricUnsupported = 0x0202,
45 FilterParseError = 0x0203,
47 KTooLarge = 0x0204,
49 Timeout = 0x0205,
51
52 LockHeld = 0x0300,
55 LockStale = 0x0301,
57 DiskFull = 0x0302,
59 FsyncFailed = 0x0303,
61 SegmentTooLarge = 0x0304,
63 ReadOnly = 0x0305,
65
66 TileTrap = 0x0400,
69 TileOom = 0x0401,
71 TileTimeout = 0x0402,
73 TileInvalidMsg = 0x0403,
75 TileUnsupportedOp = 0x0404,
77
78 KeyNotFound = 0x0500,
81 KeyExpired = 0x0501,
83 DecryptFailed = 0x0502,
85 AlgoUnsupported = 0x0503,
87 AttestationInvalid = 0x0504,
89 PlatformUnsupported = 0x0505,
91 AttestationExpired = 0x0506,
93 KeyNotBound = 0x0507,
95
96 ParentNotFound = 0x0600,
99 ParentHashMismatch = 0x0601,
101 LineageBroken = 0x0602,
103 LineageCyclic = 0x0603,
105
106 UnsignedManifest = 0x0800,
109 ContentHashMismatch = 0x0801,
111 UnknownSigner = 0x0802,
113 EpochDriftExceeded = 0x0803,
115 Level1InvalidSignature = 0x0804,
117
118 QualityBelowThreshold = 0x0900,
121 BudgetTokensExhausted = 0x0901,
123 QueryBlacklisted = 0x0902,
125
126 CowMapCorrupt = 0x0700,
129 ClusterNotFound = 0x0701,
131 ParentChainBroken = 0x0702,
133 DeltaThresholdExceeded = 0x0703,
135 SnapshotFrozen = 0x0704,
137 MembershipInvalid = 0x0705,
139 GenerationStale = 0x0706,
141 KernelBindingMismatch = 0x0707,
143 DoubleRootCorrupt = 0x0708,
145}
146
147impl ErrorCode {
148 #[inline]
150 pub const fn category(self) -> u8 {
151 (self as u16 >> 8) as u8
152 }
153
154 #[inline]
156 pub const fn is_success(self) -> bool {
157 self.category() == 0x00
158 }
159
160 #[inline]
162 pub const fn is_format_error(self) -> bool {
163 self.category() == 0x01
164 }
165
166 #[inline]
168 pub const fn is_security_error(self) -> bool {
169 self.category() == 0x08
170 }
171
172 #[inline]
174 pub const fn is_quality_error(self) -> bool {
175 self.category() == 0x09
176 }
177}
178
179impl TryFrom<u16> for ErrorCode {
180 type Error = u16;
181
182 fn try_from(value: u16) -> Result<Self, Self::Error> {
183 match value {
184 0x0000 => Ok(Self::Ok),
185 0x0001 => Ok(Self::OkPartial),
186
187 0x0100 => Ok(Self::InvalidMagic),
188 0x0101 => Ok(Self::InvalidVersion),
189 0x0102 => Ok(Self::InvalidChecksum),
190 0x0103 => Ok(Self::InvalidSignature),
191 0x0104 => Ok(Self::TruncatedSegment),
192 0x0105 => Ok(Self::InvalidManifest),
193 0x0106 => Ok(Self::ManifestNotFound),
194 0x0107 => Ok(Self::UnknownSegmentType),
195 0x0108 => Ok(Self::AlignmentError),
196
197 0x0200 => Ok(Self::DimensionMismatch),
198 0x0201 => Ok(Self::EmptyIndex),
199 0x0202 => Ok(Self::MetricUnsupported),
200 0x0203 => Ok(Self::FilterParseError),
201 0x0204 => Ok(Self::KTooLarge),
202 0x0205 => Ok(Self::Timeout),
203
204 0x0300 => Ok(Self::LockHeld),
205 0x0301 => Ok(Self::LockStale),
206 0x0302 => Ok(Self::DiskFull),
207 0x0303 => Ok(Self::FsyncFailed),
208 0x0304 => Ok(Self::SegmentTooLarge),
209 0x0305 => Ok(Self::ReadOnly),
210
211 0x0400 => Ok(Self::TileTrap),
212 0x0401 => Ok(Self::TileOom),
213 0x0402 => Ok(Self::TileTimeout),
214 0x0403 => Ok(Self::TileInvalidMsg),
215 0x0404 => Ok(Self::TileUnsupportedOp),
216
217 0x0500 => Ok(Self::KeyNotFound),
218 0x0501 => Ok(Self::KeyExpired),
219 0x0502 => Ok(Self::DecryptFailed),
220 0x0503 => Ok(Self::AlgoUnsupported),
221 0x0504 => Ok(Self::AttestationInvalid),
222 0x0505 => Ok(Self::PlatformUnsupported),
223 0x0506 => Ok(Self::AttestationExpired),
224 0x0507 => Ok(Self::KeyNotBound),
225
226 0x0600 => Ok(Self::ParentNotFound),
227 0x0601 => Ok(Self::ParentHashMismatch),
228 0x0602 => Ok(Self::LineageBroken),
229 0x0603 => Ok(Self::LineageCyclic),
230
231 0x0800 => Ok(Self::UnsignedManifest),
232 0x0801 => Ok(Self::ContentHashMismatch),
233 0x0802 => Ok(Self::UnknownSigner),
234 0x0803 => Ok(Self::EpochDriftExceeded),
235 0x0804 => Ok(Self::Level1InvalidSignature),
236
237 0x0900 => Ok(Self::QualityBelowThreshold),
238 0x0901 => Ok(Self::BudgetTokensExhausted),
239 0x0902 => Ok(Self::QueryBlacklisted),
240
241 0x0700 => Ok(Self::CowMapCorrupt),
242 0x0701 => Ok(Self::ClusterNotFound),
243 0x0702 => Ok(Self::ParentChainBroken),
244 0x0703 => Ok(Self::DeltaThresholdExceeded),
245 0x0704 => Ok(Self::SnapshotFrozen),
246 0x0705 => Ok(Self::MembershipInvalid),
247 0x0706 => Ok(Self::GenerationStale),
248 0x0707 => Ok(Self::KernelBindingMismatch),
249 0x0708 => Ok(Self::DoubleRootCorrupt),
250
251 other => Err(other),
252 }
253 }
254}
255
256#[derive(Clone, Debug, PartialEq, Eq)]
258#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
259pub enum RvfError {
260 Code(ErrorCode),
262 UnknownCode(u16),
264 BadMagic { expected: u32, got: u32 },
266 SizeMismatch { expected: usize, got: usize },
268 InvalidEnumValue { type_name: &'static str, value: u64 },
270 Security(crate::security::SecurityError),
272 QualityBelowThreshold {
275 quality: crate::quality::ResponseQuality,
276 reason: &'static str,
277 },
278}
279
280impl core::fmt::Display for RvfError {
281 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
282 match self {
283 Self::Code(c) => write!(f, "RVF error code 0x{:04X}", *c as u16),
284 Self::UnknownCode(v) => write!(f, "unknown RVF error code 0x{v:04X}"),
285 Self::BadMagic { expected, got } => {
286 write!(f, "bad magic: expected 0x{expected:08X}, got 0x{got:08X}")
287 }
288 Self::SizeMismatch { expected, got } => {
289 write!(f, "size mismatch: expected {expected}, got {got}")
290 }
291 Self::InvalidEnumValue { type_name, value } => {
292 write!(f, "invalid {type_name} value: {value}")
293 }
294 Self::Security(e) => write!(f, "security error: {e}"),
295 Self::QualityBelowThreshold { quality, reason } => {
296 write!(f, "quality below threshold ({quality:?}): {reason}")
297 }
298 }
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305 use alloc::format;
306
307 #[test]
308 fn error_code_round_trip_all() {
309 let codes: &[(u16, ErrorCode)] = &[
310 (0x0000, ErrorCode::Ok),
311 (0x0001, ErrorCode::OkPartial),
312 (0x0100, ErrorCode::InvalidMagic),
313 (0x0101, ErrorCode::InvalidVersion),
314 (0x0102, ErrorCode::InvalidChecksum),
315 (0x0103, ErrorCode::InvalidSignature),
316 (0x0104, ErrorCode::TruncatedSegment),
317 (0x0105, ErrorCode::InvalidManifest),
318 (0x0106, ErrorCode::ManifestNotFound),
319 (0x0107, ErrorCode::UnknownSegmentType),
320 (0x0108, ErrorCode::AlignmentError),
321 (0x0200, ErrorCode::DimensionMismatch),
322 (0x0201, ErrorCode::EmptyIndex),
323 (0x0202, ErrorCode::MetricUnsupported),
324 (0x0203, ErrorCode::FilterParseError),
325 (0x0204, ErrorCode::KTooLarge),
326 (0x0205, ErrorCode::Timeout),
327 (0x0300, ErrorCode::LockHeld),
328 (0x0301, ErrorCode::LockStale),
329 (0x0302, ErrorCode::DiskFull),
330 (0x0303, ErrorCode::FsyncFailed),
331 (0x0304, ErrorCode::SegmentTooLarge),
332 (0x0305, ErrorCode::ReadOnly),
333 (0x0400, ErrorCode::TileTrap),
334 (0x0401, ErrorCode::TileOom),
335 (0x0402, ErrorCode::TileTimeout),
336 (0x0403, ErrorCode::TileInvalidMsg),
337 (0x0404, ErrorCode::TileUnsupportedOp),
338 (0x0500, ErrorCode::KeyNotFound),
339 (0x0501, ErrorCode::KeyExpired),
340 (0x0502, ErrorCode::DecryptFailed),
341 (0x0503, ErrorCode::AlgoUnsupported),
342 (0x0504, ErrorCode::AttestationInvalid),
343 (0x0505, ErrorCode::PlatformUnsupported),
344 (0x0506, ErrorCode::AttestationExpired),
345 (0x0507, ErrorCode::KeyNotBound),
346 (0x0600, ErrorCode::ParentNotFound),
347 (0x0601, ErrorCode::ParentHashMismatch),
348 (0x0602, ErrorCode::LineageBroken),
349 (0x0603, ErrorCode::LineageCyclic),
350 (0x0800, ErrorCode::UnsignedManifest),
351 (0x0801, ErrorCode::ContentHashMismatch),
352 (0x0802, ErrorCode::UnknownSigner),
353 (0x0803, ErrorCode::EpochDriftExceeded),
354 (0x0804, ErrorCode::Level1InvalidSignature),
355 (0x0900, ErrorCode::QualityBelowThreshold),
356 (0x0901, ErrorCode::BudgetTokensExhausted),
357 (0x0902, ErrorCode::QueryBlacklisted),
358 (0x0700, ErrorCode::CowMapCorrupt),
359 (0x0701, ErrorCode::ClusterNotFound),
360 (0x0702, ErrorCode::ParentChainBroken),
361 (0x0703, ErrorCode::DeltaThresholdExceeded),
362 (0x0704, ErrorCode::SnapshotFrozen),
363 (0x0705, ErrorCode::MembershipInvalid),
364 (0x0706, ErrorCode::GenerationStale),
365 (0x0707, ErrorCode::KernelBindingMismatch),
366 (0x0708, ErrorCode::DoubleRootCorrupt),
367 ];
368 for &(raw, expected) in codes {
369 assert_eq!(ErrorCode::try_from(raw), Ok(expected), "code 0x{raw:04X}");
370 assert_eq!(expected as u16, raw);
371 }
372 }
373
374 #[test]
375 fn unknown_code() {
376 assert_eq!(ErrorCode::try_from(0x9999), Err(0x9999));
377 }
378
379 #[test]
380 fn category_extraction() {
381 assert_eq!(ErrorCode::Ok.category(), 0x00);
382 assert_eq!(ErrorCode::InvalidMagic.category(), 0x01);
383 assert_eq!(ErrorCode::DimensionMismatch.category(), 0x02);
384 assert_eq!(ErrorCode::LockHeld.category(), 0x03);
385 assert_eq!(ErrorCode::TileTrap.category(), 0x04);
386 assert_eq!(ErrorCode::KeyNotFound.category(), 0x05);
387 assert_eq!(ErrorCode::ParentNotFound.category(), 0x06);
388 assert_eq!(ErrorCode::CowMapCorrupt.category(), 0x07);
389 assert_eq!(ErrorCode::UnsignedManifest.category(), 0x08);
390 assert_eq!(ErrorCode::QualityBelowThreshold.category(), 0x09);
391 }
392
393 #[test]
394 fn security_error_check() {
395 assert!(ErrorCode::UnsignedManifest.is_security_error());
396 assert!(!ErrorCode::Ok.is_security_error());
397 }
398
399 #[test]
400 fn quality_error_check() {
401 assert!(ErrorCode::QualityBelowThreshold.is_quality_error());
402 assert!(!ErrorCode::Ok.is_quality_error());
403 }
404
405 #[test]
406 fn success_check() {
407 assert!(ErrorCode::Ok.is_success());
408 assert!(ErrorCode::OkPartial.is_success());
409 assert!(!ErrorCode::InvalidMagic.is_success());
410 }
411
412 #[test]
413 fn format_error_check() {
414 assert!(ErrorCode::InvalidMagic.is_format_error());
415 assert!(!ErrorCode::Ok.is_format_error());
416 assert!(!ErrorCode::DimensionMismatch.is_format_error());
417 }
418
419 #[test]
420 fn rvf_error_display() {
421 let e = RvfError::BadMagic {
422 expected: 0x52564653,
423 got: 0x00000000,
424 };
425 let s = format!("{e}");
426 assert!(s.contains("bad magic"));
427 assert!(s.contains("52564653"));
428 }
429
430 #[test]
431 fn cow_error_check() {
432 assert_eq!(ErrorCode::CowMapCorrupt as u16, 0x0700);
433 assert_eq!(ErrorCode::ClusterNotFound as u16, 0x0701);
434 assert_eq!(ErrorCode::ParentChainBroken as u16, 0x0702);
435 assert_eq!(ErrorCode::DeltaThresholdExceeded as u16, 0x0703);
436 assert_eq!(ErrorCode::SnapshotFrozen as u16, 0x0704);
437 assert_eq!(ErrorCode::MembershipInvalid as u16, 0x0705);
438 assert_eq!(ErrorCode::GenerationStale as u16, 0x0706);
439 assert_eq!(ErrorCode::KernelBindingMismatch as u16, 0x0707);
440 assert_eq!(ErrorCode::DoubleRootCorrupt as u16, 0x0708);
441 assert_eq!(ErrorCode::CowMapCorrupt.category(), 0x07);
443 assert_eq!(ErrorCode::DoubleRootCorrupt.category(), 0x07);
444 }
445
446 #[test]
447 fn error_codes_match_spec() {
448 assert_eq!(ErrorCode::InvalidMagic as u16, 0x0100);
449 assert_eq!(ErrorCode::InvalidChecksum as u16, 0x0102);
450 assert_eq!(ErrorCode::ManifestNotFound as u16, 0x0106);
451 assert_eq!(ErrorCode::AlgoUnsupported as u16, 0x0503);
452 }
453}