use snafu::Backtrace;
use snafu::Snafu;
use crate::registry::TcSchemeKind;
#[derive(Snafu, Debug)]
#[snafu(visibility(pub))]
pub enum Error {
#[snafu(display("NULL pointer on parameter '{}'", param))]
NullPointer {
param: &'static str,
backtrace: Backtrace,
},
#[snafu(display("Invalid UTF-8"))]
InvalidUTF8 {
backtrace: Backtrace,
source: std::str::Utf8Error,
},
#[snafu(display("Interior NUL byte in C string"))]
NulByte {
backtrace: Backtrace,
source: std::ffi::NulError,
},
#[snafu(display("Party index {} out of range (party count {})", idx, count))]
PartyIndexOutOfRange {
idx: usize,
count: usize,
backtrace: Backtrace,
},
#[snafu(display("Party list is empty"))]
EmptyPartyList { backtrace: Backtrace },
#[snafu(display("Threshold {} is below the minimum of 1", threshold))]
ThresholdTooSmall {
threshold: u32,
backtrace: Backtrace,
},
#[snafu(display("Threshold {} exceeds party count {}", threshold, party_count))]
ThresholdTooLarge {
threshold: u32,
party_count: usize,
backtrace: Backtrace,
},
#[snafu(display("Duplicate party id '{}'", id))]
DuplicatePartyId { id: String, backtrace: Backtrace },
#[snafu(display("this_party_idx {} out of range (party count {})", idx, party_count))]
ThisPartyIdxOutOfRange {
idx: usize,
party_count: usize,
backtrace: Backtrace,
},
#[snafu(display("Unknown threshold scheme '{}'", name))]
SchemeNotFound { name: String, backtrace: Backtrace },
#[snafu(display("Session is not complete"))]
SessionNotComplete { backtrace: Backtrace },
#[snafu(display("Session is already complete"))]
SessionAlreadyComplete { backtrace: Backtrace },
#[snafu(display("Round counter overflowed at round {}", round))]
RoundOverflow { round: u8, backtrace: Backtrace },
#[snafu(display("Session is not a DKG session (kind {:?})", kind))]
NotADkgSession {
kind: TcSchemeKind,
backtrace: Backtrace,
},
#[snafu(display("Share scheme mismatch: expected '{}', got '{}'", expected, actual))]
ShareSchemeMismatch {
expected: String,
actual: String,
backtrace: Backtrace,
},
#[snafu(display("Share bytes truncated: need {} bytes, have {}", needed, have))]
ShareTruncated {
needed: usize,
have: usize,
backtrace: Backtrace,
},
#[snafu(display("Share scheme name is not valid UTF-8"))]
ShareInvalidScheme { backtrace: Backtrace },
#[snafu(display("Insufficient buffer"))]
InsufficientBuffer { backtrace: Backtrace },
#[snafu(display("Scheme plugin returned error code {}", code))]
SchemeInternalError { code: u32, backtrace: Backtrace },
}
impl Error {
pub fn code(&self) -> u32 {
error_code(self)
}
}
#[allow(non_camel_case_types)]
#[repr(u32)]
pub enum ErrorCode {
UNKNOWN = 0x1000,
NULL_POINTER = 0x1001,
INVALID_UTF8 = 0x1002,
NUL_BYTE = 0x1003,
PARTY_INDEX_OUT_OF_RANGE = 0x1010,
EMPTY_PARTY_LIST = 0x1011,
THRESHOLD_TOO_SMALL = 0x1012,
THRESHOLD_TOO_LARGE = 0x1013,
DUPLICATE_PARTY_ID = 0x1014,
THIS_PARTY_IDX_OUT_OF_RANGE = 0x1015,
SCHEME_NOT_FOUND = 0x1020,
SESSION_NOT_COMPLETE = 0x1021,
SESSION_ALREADY_COMPLETE = 0x1022,
ROUND_OVERFLOW = 0x1023,
NOT_A_DKG_SESSION = 0x1024,
SHARE_SCHEME_MISMATCH = 0x1030,
SHARE_TRUNCATED = 0x1031,
SHARE_INVALID_SCHEME = 0x1032,
INSUFFICIENT_BUFFER = 0x1040,
SCHEME_INTERNAL_ERROR = 0x1041,
}
fn error_code(error: &Error) -> u32 {
match error {
Error::NullPointer { .. } => ErrorCode::NULL_POINTER.into(),
Error::InvalidUTF8 { .. } => ErrorCode::INVALID_UTF8.into(),
Error::NulByte { .. } => ErrorCode::NUL_BYTE.into(),
Error::PartyIndexOutOfRange { .. } => ErrorCode::PARTY_INDEX_OUT_OF_RANGE.into(),
Error::EmptyPartyList { .. } => ErrorCode::EMPTY_PARTY_LIST.into(),
Error::ThresholdTooSmall { .. } => ErrorCode::THRESHOLD_TOO_SMALL.into(),
Error::ThresholdTooLarge { .. } => ErrorCode::THRESHOLD_TOO_LARGE.into(),
Error::DuplicatePartyId { .. } => ErrorCode::DUPLICATE_PARTY_ID.into(),
Error::ThisPartyIdxOutOfRange { .. } => ErrorCode::THIS_PARTY_IDX_OUT_OF_RANGE.into(),
Error::SchemeNotFound { .. } => ErrorCode::SCHEME_NOT_FOUND.into(),
Error::SessionNotComplete { .. } => ErrorCode::SESSION_NOT_COMPLETE.into(),
Error::SessionAlreadyComplete { .. } => ErrorCode::SESSION_ALREADY_COMPLETE.into(),
Error::RoundOverflow { .. } => ErrorCode::ROUND_OVERFLOW.into(),
Error::NotADkgSession { .. } => ErrorCode::NOT_A_DKG_SESSION.into(),
Error::ShareSchemeMismatch { .. } => ErrorCode::SHARE_SCHEME_MISMATCH.into(),
Error::ShareTruncated { .. } => ErrorCode::SHARE_TRUNCATED.into(),
Error::ShareInvalidScheme { .. } => ErrorCode::SHARE_INVALID_SCHEME.into(),
Error::InsufficientBuffer { .. } => ErrorCode::INSUFFICIENT_BUFFER.into(),
Error::SchemeInternalError { .. } => ErrorCode::SCHEME_INTERNAL_ERROR.into(),
}
}
impl From<ErrorCode> for u32 {
#[inline]
fn from(code: ErrorCode) -> u32 {
code as u32
}
}
impl From<Error> for u32 {
#[inline]
fn from(err: Error) -> u32 {
error_code(&err)
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_code_is_disjoint_from_core() {
let err = SchemeNotFoundSnafu {
name: "x".to_string(),
}
.build();
assert!(err.code() >= 0x1000);
}
#[test]
fn null_pointer_code() {
let err = NullPointerSnafu { param: "x" }.build();
assert_eq!(err.code(), ErrorCode::NULL_POINTER as u32);
}
}