use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum BitBoxDeviceError {
#[error("error code not recognized")]
Unknown(i32),
#[error("invalid input")]
InvalidInput,
#[error("memory")]
Memory,
#[error("generic error")]
Generic,
#[error("aborted by the user")]
UserAbort,
#[error("can't call this endpoint: wrong state")]
InvalidState,
#[error("function disabled")]
Disabled,
#[error("duplicate entry")]
Duplicate,
#[error("noise encryption failed")]
NoiseEncrypt,
#[error("noise decryption failed")]
NoiseDecrypt,
}
impl BitBoxDeviceError {
pub fn from_code(code: i32) -> Self {
match code {
101 => Self::InvalidInput,
102 => Self::Memory,
103 => Self::Generic,
104 => Self::UserAbort,
105 => Self::InvalidState,
106 => Self::Disabled,
107 => Self::Duplicate,
108 => Self::NoiseEncrypt,
109 => Self::NoiseDecrypt,
_ => Self::Unknown(code),
}
}
pub fn code(&self) -> i32 {
match self {
Self::InvalidInput => 101,
Self::Memory => 102,
Self::Generic => 103,
Self::UserAbort => 104,
Self::InvalidState => 105,
Self::Disabled => 106,
Self::Duplicate => 107,
Self::NoiseEncrypt => 108,
Self::NoiseDecrypt => 109,
Self::Unknown(code) => *code,
}
}
}
#[derive(Error, Debug)]
pub enum BitBoxError {
#[error("firmware version {0} required")]
Version(
&'static str,
),
#[error("bitbox device error: {}", .1.as_deref().map_or_else(|| .0.to_string(), str::to_owned))]
Device(
BitBoxDeviceError,
Option<String>,
),
#[error("noise channel error: {0}")]
Noise(
&'static str,
),
#[error("noise config error: {0}")]
NoiseConfig(
String,
),
#[error("pairing code rejected by user")]
NoisePairingRejected,
#[error("BitBox returned an unexpected response")]
UnexpectedResponse,
#[error("protobuf message could not be decoded: {0}")]
ProtobufDecode(
String,
),
#[error("protobuf message could not be encoded: {0}")]
ProtobufEncode(
String,
),
#[error("PSBT error: {0}")]
Psbt(
String,
),
#[error("unexpected signature format returned by BitBox")]
InvalidSignature,
#[error("Antiklepto verification failed: {0}")]
AntiKlepto(
String,
),
#[error("Bitcoin transaction signing error: {0}")]
BtcSign(
String,
),
#[error("invalid input: {0}")]
InvalidInput(
&'static str,
),
#[error("missing command info: {0}")]
MissingContext(&'static str),
#[error("missing command info: {0}")]
Unsupported(&'static str),
#[error("The BitBox02 must be wiped before setup.")]
AlreadyInitialized,
#[error("The BitBox02 must be initialized first.")]
NotInitialized,
#[error("unsupported display address: {0}")]
UnsupportedDisplayAddress(
&'static str,
),
#[error("communication framing error: {0}")]
Framing(
&'static str,
),
#[error("transport error: {0}")]
Transport(
String,
),
#[error("transport error: {0}")]
Disconnected(String),
}
impl From<BitBoxDeviceError> for BitBoxError {
fn from(error: BitBoxDeviceError) -> Self {
BitBoxError::Device(error, None)
}
}
impl BitBoxError {
pub fn from_reply(code: i32, message: String) -> Self {
BitBoxError::Device(
BitBoxDeviceError::from_code(code),
Some(message).filter(|message| !message.is_empty()),
)
}
}
impl From<prost::DecodeError> for BitBoxError {
fn from(e: prost::DecodeError) -> Self {
BitBoxError::ProtobufDecode(e.to_string())
}
}
impl From<prost::EncodeError> for BitBoxError {
fn from(e: prost::EncodeError) -> Self {
BitBoxError::ProtobufEncode(e.to_string())
}
}