1use snafu::Backtrace;
8use snafu::Snafu;
9
10use crate::registry::TcSchemeKind;
11
12#[derive(Snafu, Debug)]
13#[snafu(visibility(pub))]
14pub enum Error {
15 #[snafu(display("NULL pointer on parameter '{}'", param))]
16 NullPointer {
17 param: &'static str,
18 backtrace: Backtrace,
19 },
20 #[snafu(display("Invalid UTF-8"))]
21 InvalidUTF8 {
22 backtrace: Backtrace,
23 source: std::str::Utf8Error,
24 },
25 #[snafu(display("Interior NUL byte in C string"))]
26 NulByte {
27 backtrace: Backtrace,
28 source: std::ffi::NulError,
29 },
30
31 #[snafu(display("Party index {} out of range (party count {})", idx, count))]
32 PartyIndexOutOfRange {
33 idx: usize,
34 count: usize,
35 backtrace: Backtrace,
36 },
37 #[snafu(display("Party list is empty"))]
38 EmptyPartyList { backtrace: Backtrace },
39 #[snafu(display("Threshold {} is below the minimum of 1", threshold))]
40 ThresholdTooSmall {
41 threshold: u32,
42 backtrace: Backtrace,
43 },
44 #[snafu(display("Threshold {} exceeds party count {}", threshold, party_count))]
45 ThresholdTooLarge {
46 threshold: u32,
47 party_count: usize,
48 backtrace: Backtrace,
49 },
50 #[snafu(display("Duplicate party id '{}'", id))]
51 DuplicatePartyId { id: String, backtrace: Backtrace },
52 #[snafu(display("this_party_idx {} out of range (party count {})", idx, party_count))]
53 ThisPartyIdxOutOfRange {
54 idx: usize,
55 party_count: usize,
56 backtrace: Backtrace,
57 },
58
59 #[snafu(display("Unknown threshold scheme '{}'", name))]
60 SchemeNotFound { name: String, backtrace: Backtrace },
61 #[snafu(display("Session is not complete"))]
62 SessionNotComplete { backtrace: Backtrace },
63 #[snafu(display("Session is already complete"))]
64 SessionAlreadyComplete { backtrace: Backtrace },
65 #[snafu(display("Round counter overflowed at round {}", round))]
66 RoundOverflow { round: u8, backtrace: Backtrace },
67 #[snafu(display("Session is not a DKG session (kind {:?})", kind))]
68 NotADkgSession {
69 kind: TcSchemeKind,
70 backtrace: Backtrace,
71 },
72
73 #[snafu(display("Share scheme mismatch: expected '{}', got '{}'", expected, actual))]
74 ShareSchemeMismatch {
75 expected: String,
76 actual: String,
77 backtrace: Backtrace,
78 },
79 #[snafu(display("Share bytes truncated: need {} bytes, have {}", needed, have))]
80 ShareTruncated {
81 needed: usize,
82 have: usize,
83 backtrace: Backtrace,
84 },
85 #[snafu(display("Share scheme name is not valid UTF-8"))]
86 ShareInvalidScheme { backtrace: Backtrace },
87
88 #[snafu(display("Insufficient buffer"))]
89 InsufficientBuffer { backtrace: Backtrace },
90 #[snafu(display("Scheme plugin returned error code {}", code))]
91 SchemeInternalError { code: u32, backtrace: Backtrace },
92}
93
94impl Error {
95 pub fn code(&self) -> u32 {
97 error_code(self)
98 }
99}
100
101#[allow(non_camel_case_types)]
105#[repr(u32)]
106pub enum ErrorCode {
107 UNKNOWN = 0x1000,
108 NULL_POINTER = 0x1001,
109 INVALID_UTF8 = 0x1002,
110 NUL_BYTE = 0x1003,
111
112 PARTY_INDEX_OUT_OF_RANGE = 0x1010,
113 EMPTY_PARTY_LIST = 0x1011,
114 THRESHOLD_TOO_SMALL = 0x1012,
115 THRESHOLD_TOO_LARGE = 0x1013,
116 DUPLICATE_PARTY_ID = 0x1014,
117 THIS_PARTY_IDX_OUT_OF_RANGE = 0x1015,
118
119 SCHEME_NOT_FOUND = 0x1020,
120 SESSION_NOT_COMPLETE = 0x1021,
121 SESSION_ALREADY_COMPLETE = 0x1022,
122 ROUND_OVERFLOW = 0x1023,
123 NOT_A_DKG_SESSION = 0x1024,
124
125 SHARE_SCHEME_MISMATCH = 0x1030,
126 SHARE_TRUNCATED = 0x1031,
127 SHARE_INVALID_SCHEME = 0x1032,
128
129 INSUFFICIENT_BUFFER = 0x1040,
130 SCHEME_INTERNAL_ERROR = 0x1041,
131}
132
133fn error_code(error: &Error) -> u32 {
134 match error {
135 Error::NullPointer { .. } => ErrorCode::NULL_POINTER.into(),
136 Error::InvalidUTF8 { .. } => ErrorCode::INVALID_UTF8.into(),
137 Error::NulByte { .. } => ErrorCode::NUL_BYTE.into(),
138
139 Error::PartyIndexOutOfRange { .. } => ErrorCode::PARTY_INDEX_OUT_OF_RANGE.into(),
140 Error::EmptyPartyList { .. } => ErrorCode::EMPTY_PARTY_LIST.into(),
141 Error::ThresholdTooSmall { .. } => ErrorCode::THRESHOLD_TOO_SMALL.into(),
142 Error::ThresholdTooLarge { .. } => ErrorCode::THRESHOLD_TOO_LARGE.into(),
143 Error::DuplicatePartyId { .. } => ErrorCode::DUPLICATE_PARTY_ID.into(),
144 Error::ThisPartyIdxOutOfRange { .. } => ErrorCode::THIS_PARTY_IDX_OUT_OF_RANGE.into(),
145
146 Error::SchemeNotFound { .. } => ErrorCode::SCHEME_NOT_FOUND.into(),
147 Error::SessionNotComplete { .. } => ErrorCode::SESSION_NOT_COMPLETE.into(),
148 Error::SessionAlreadyComplete { .. } => ErrorCode::SESSION_ALREADY_COMPLETE.into(),
149 Error::RoundOverflow { .. } => ErrorCode::ROUND_OVERFLOW.into(),
150 Error::NotADkgSession { .. } => ErrorCode::NOT_A_DKG_SESSION.into(),
151
152 Error::ShareSchemeMismatch { .. } => ErrorCode::SHARE_SCHEME_MISMATCH.into(),
153 Error::ShareTruncated { .. } => ErrorCode::SHARE_TRUNCATED.into(),
154 Error::ShareInvalidScheme { .. } => ErrorCode::SHARE_INVALID_SCHEME.into(),
155
156 Error::InsufficientBuffer { .. } => ErrorCode::INSUFFICIENT_BUFFER.into(),
157 Error::SchemeInternalError { .. } => ErrorCode::SCHEME_INTERNAL_ERROR.into(),
158 }
159}
160
161impl From<ErrorCode> for u32 {
162 #[inline]
163 fn from(code: ErrorCode) -> u32 {
164 code as u32
165 }
166}
167
168impl From<Error> for u32 {
169 #[inline]
170 fn from(err: Error) -> u32 {
171 error_code(&err)
172 }
173}
174
175pub type Result<T> = std::result::Result<T, Error>;
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[test]
182 fn error_code_is_disjoint_from_core() {
183 let err = SchemeNotFoundSnafu {
185 name: "x".to_string(),
186 }
187 .build();
188 assert!(err.code() >= 0x1000);
189 }
190
191 #[test]
192 fn null_pointer_code() {
193 let err = NullPointerSnafu { param: "x" }.build();
194 assert_eq!(err.code(), ErrorCode::NULL_POINTER as u32);
195 }
196}