use crate::{chain, prelude::*};
use abscissa_core::error::{BoxError, Context};
use std::{
any::Any,
fmt::{self, Display},
io,
ops::Deref,
};
use thiserror::Error;
#[derive(Copy, Clone, Eq, PartialEq, Debug, Error)]
pub enum ErrorKind {
#[error("access denied")]
AccessError,
#[error("chain ID error")]
ChainIdError,
#[error("config error")]
ConfigError,
#[error("cryptographic error")]
CryptoError,
#[error("attempted double sign")]
DoubleSign,
#[error("requested signature above stop height")]
ExceedMaxHeight,
#[cfg(feature = "fortanixdsm")]
#[error("Fortanix DSM error")]
FortanixDsmError,
#[error("subcommand hook failed")]
HookError,
#[error("invalid key")]
InvalidKey,
#[error("invalid consensus message")]
InvalidMessageError,
#[error("I/O error")]
IoError,
#[error("internal crash")]
PanicError,
#[error("parse error")]
ParseError,
#[error("internal state poisoned")]
PoisonError,
#[error("protocol error")]
ProtocolError,
#[error("serialization error")]
SerializationError,
#[error("signing operation failed")]
SigningError,
#[error("Tendermint error")]
TendermintError,
#[error("verification failed")]
VerificationError,
#[cfg(feature = "yubihsm")]
#[error("YubiHSM error")]
YubihsmError,
}
impl ErrorKind {
pub fn context(self, source: impl Into<BoxError>) -> Context<ErrorKind> {
Context::new(self, Some(source.into()))
}
}
#[derive(Debug)]
pub struct Error(Box<Context<ErrorKind>>);
impl Error {
pub fn from_panic(panic_msg: Box<dyn Any>) -> Self {
let err_msg = if let Some(msg) = panic_msg.downcast_ref::<String>() {
msg.as_ref()
} else if let Some(msg) = panic_msg.downcast_ref::<&str>() {
msg
} else {
"unknown cause"
};
let kind = if err_msg.contains("PoisonError") {
ErrorKind::PoisonError
} else {
ErrorKind::PanicError
};
format_err!(kind, err_msg).into()
}
}
impl Deref for Error {
type Target = Context<ErrorKind>;
fn deref(&self) -> &Context<ErrorKind> {
&self.0
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Context::new(kind, None).into()
}
}
impl From<Context<ErrorKind>> for Error {
fn from(context: Context<ErrorKind>) -> Self {
Error(Box::new(context))
}
}
impl From<io::Error> for Error {
fn from(other: io::Error) -> Self {
ErrorKind::IoError.context(other).into()
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.source()
}
}
impl From<prost::DecodeError> for Error {
fn from(other: prost::DecodeError) -> Self {
ErrorKind::ProtocolError.context(other).into()
}
}
impl From<prost::EncodeError> for Error {
fn from(other: prost::EncodeError) -> Self {
ErrorKind::ProtocolError.context(other).into()
}
}
impl From<serde_json::error::Error> for Error {
fn from(other: serde_json::error::Error) -> Self {
ErrorKind::SerializationError.context(other).into()
}
}
impl From<signature::Error> for Error {
fn from(other: signature::Error) -> Self {
ErrorKind::CryptoError.context(other).into()
}
}
impl From<tendermint::Error> for Error {
fn from(other: tendermint::error::Error) -> Self {
ErrorKind::TendermintError.context(other).into()
}
}
impl From<chain::state::StateError> for Error {
fn from(other: chain::state::StateError) -> Self {
ErrorKind::DoubleSign.context(other).into()
}
}