feat: use thiserror library to handle error creation

This commit is contained in:
thunderbiscuit 2024-03-25 12:19:47 -04:00
parent 06fa9d751b
commit 61e58240fc
No known key found for this signature in database
GPG Key ID: 88253696EB836462
3 changed files with 80 additions and 130 deletions

9
bdk-ffi/Cargo.lock generated
View File

@ -161,6 +161,7 @@ dependencies = [
"bdk", "bdk",
"bdk_esplora", "bdk_esplora",
"bdk_file_store", "bdk_file_store",
"thiserror",
"uniffi", "uniffi",
] ]
@ -883,18 +884,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.56" version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.56" version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -24,6 +24,7 @@ bdk_esplora = { version = "0.9.0", default-features = false, features = ["std",
bdk_file_store = { version = "0.7.0" } bdk_file_store = { version = "0.7.0" }
uniffi = { version = "=0.26.1" } uniffi = { version = "=0.26.1" }
thiserror = "1.0.58"
[build-dependencies] [build-dependencies]
uniffi = { version = "=0.26.1", features = ["build"] } uniffi = { version = "=0.26.1", features = ["build"] }

View File

@ -3,8 +3,6 @@ use crate::bitcoin::OutPoint;
use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError;
use bdk_esplora::esplora_client::Error as BdkEsploraError; use bdk_esplora::esplora_client::Error as BdkEsploraError;
use std::fmt;
use bdk::bitcoin::Network; use bdk::bitcoin::Network;
use bdk::descriptor::DescriptorError; use bdk::descriptor::DescriptorError;
use bdk::wallet::error::{BuildFeeBumpError, CreateTxError}; use bdk::wallet::error::{BuildFeeBumpError, CreateTxError};
@ -14,77 +12,93 @@ use bdk_file_store::FileError as BdkFileError;
use bdk_file_store::IterError; use bdk_file_store::IterError;
use std::convert::Infallible; use std::convert::Infallible;
#[derive(Debug)] #[derive(Debug, thiserror::Error)]
pub enum Alpha3Error { pub enum Alpha3Error {
#[error("generic error in ffi")]
Generic, Generic,
} }
impl fmt::Display for Alpha3Error { #[derive(Debug, thiserror::Error)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { pub enum CalculateFeeError {
match self { #[error("missing transaction output: {out_points:?}")]
Alpha3Error::Generic => write!(f, "Error in FFI"), MissingTxOut { out_points: Vec<OutPoint> },
}
} #[error("negative fee value: {fee}")]
NegativeFee { fee: i64 },
} }
impl std::error::Error for Alpha3Error {} #[derive(Debug, thiserror::Error)]
#[derive(Debug)]
pub enum WalletCreationError { pub enum WalletCreationError {
// Errors coming from the FileError enum // Errors coming from the FileError enum
Io { #[error("io error trying to read file: {e}")]
e: String, Io { e: String },
},
InvalidMagicBytes { #[error("file has invalid magic bytes: expected={expected:?} got={got:?}")]
got: Vec<u8>, InvalidMagicBytes { got: Vec<u8>, expected: Vec<u8> },
expected: Vec<u8>,
},
// Errors coming from the NewOrLoadError enum // Errors coming from the NewOrLoadError enum
#[error("error with descriptor")]
Descriptor, Descriptor,
#[error("failed to write to persistence")]
Write, Write,
#[error("failed to load from persistence")]
Load, Load,
#[error("wallet is not initialized, persistence backend is empty")]
NotInitialized, NotInitialized,
#[error("loaded genesis hash does not match the expected one")]
LoadedGenesisDoesNotMatch, LoadedGenesisDoesNotMatch,
#[error("loaded network type is not {expected}, got {got:?}")]
LoadedNetworkDoesNotMatch { LoadedNetworkDoesNotMatch {
expected: Network, expected: Network,
got: Option<Network>, got: Option<Network>,
}, },
} }
impl fmt::Display for WalletCreationError { #[derive(Debug, thiserror::Error)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { pub enum EsploraError {
match self { #[error("ureq error: {error_message}")]
Self::Io { e } => write!(f, "io error trying to read file: {}", e), Ureq { error_message: String },
Self::InvalidMagicBytes { got, expected } => write!(
f,
"file has invalid magic bytes: expected={:?} got={:?}",
expected, got,
),
Self::Descriptor => write!(f, "error with descriptor"),
Self::Write => write!(f, "failed to write to persistence"),
Self::Load => write!(f, "failed to load from persistence"),
Self::NotInitialized => {
write!(f, "wallet is not initialized, persistence backend is empty")
}
Self::LoadedGenesisDoesNotMatch => {
write!(f, "loaded genesis hash does not match the expected one")
}
Self::LoadedNetworkDoesNotMatch { expected, got } => {
write!(f, "loaded network type is not {}, got {:?}", expected, got)
}
}
}
}
impl std::error::Error for WalletCreationError {} #[error("ureq transport error: {error_message}")]
UreqTransport { error_message: String },
#[error("http error with status code: {status_code}")]
Http { status_code: u16 },
#[error("io error: {error_message}")]
Io { error_message: String },
#[error("no header found in the response")]
NoHeader,
#[error("parsing error: {error_message}")]
Parsing { error_message: String },
#[error("bitcoin encoding error: {error_message}")]
BitcoinEncoding { error_message: String },
#[error("hex decoding error: {error_message}")]
Hex { error_message: String },
#[error("transaction not found")]
TransactionNotFound,
#[error("header height {height} not found")]
HeaderHeightNotFound { height: u32 },
#[error("header hash not found")]
HeaderHashNotFound,
}
impl From<BdkFileError> for WalletCreationError { impl From<BdkFileError> for WalletCreationError {
fn from(error: BdkFileError) -> Self { fn from(error: BdkFileError) -> Self {
match error { match error {
BdkFileError::Io(_) => WalletCreationError::Io { BdkFileError::Io(e) => WalletCreationError::Io { e: e.to_string() },
e: "io error trying to read file".to_string(),
},
BdkFileError::InvalidMagicBytes { got, expected } => { BdkFileError::InvalidMagicBytes { got, expected } => {
WalletCreationError::InvalidMagicBytes { got, expected } WalletCreationError::InvalidMagicBytes { got, expected }
} }
@ -157,23 +171,6 @@ impl From<CreateTxError<std::io::Error>> for Alpha3Error {
} }
} }
#[derive(Debug)]
pub enum CalculateFeeError {
MissingTxOut { out_points: Vec<OutPoint> },
NegativeFee { fee: i64 },
}
impl fmt::Display for CalculateFeeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CalculateFeeError::MissingTxOut { out_points } => {
write!(f, "Missing transaction output: {:?}", out_points)
}
CalculateFeeError::NegativeFee { fee } => write!(f, "Negative fee value: {}", fee),
}
}
}
impl From<BdkCalculateFeeError> for CalculateFeeError { impl From<BdkCalculateFeeError> for CalculateFeeError {
fn from(error: BdkCalculateFeeError) -> Self { fn from(error: BdkCalculateFeeError) -> Self {
match error { match error {
@ -185,53 +182,6 @@ impl From<BdkCalculateFeeError> for CalculateFeeError {
} }
} }
impl std::error::Error for CalculateFeeError {}
#[derive(Debug)]
pub enum EsploraError {
Ureq { error_message: String },
UreqTransport { error_message: String },
Http { status_code: u16 },
Io { error_message: String },
NoHeader,
Parsing { error_message: String },
BitcoinEncoding { error_message: String },
Hex { error_message: String },
TransactionNotFound,
HeaderHeightNotFound { height: u32 },
HeaderHashNotFound,
}
impl fmt::Display for EsploraError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
EsploraError::Ureq { error_message } => write!(f, "Ureq error: {}", error_message),
EsploraError::UreqTransport { error_message } => {
write!(f, "Ureq transport error: {}", error_message)
}
EsploraError::Http { status_code } => {
write!(f, "HTTP error with status code: {}", status_code)
}
EsploraError::Io { error_message } => write!(f, "IO error: {}", error_message),
EsploraError::NoHeader => write!(f, "No header found in the response"),
EsploraError::Parsing { error_message } => {
write!(f, "Parsing error: {}", error_message)
}
EsploraError::BitcoinEncoding { error_message } => {
write!(f, "Bitcoin encoding error: {}", error_message)
}
EsploraError::Hex { error_message } => {
write!(f, "Hex decoding error: {}", error_message)
}
EsploraError::TransactionNotFound => write!(f, "Transaction not found"),
EsploraError::HeaderHeightNotFound { height } => {
write!(f, "Header height {} not found", height)
}
EsploraError::HeaderHashNotFound => write!(f, "Header hash not found"),
}
}
}
impl From<BdkEsploraError> for EsploraError { impl From<BdkEsploraError> for EsploraError {
fn from(error: BdkEsploraError) -> Self { fn from(error: BdkEsploraError) -> Self {
match error { match error {
@ -264,8 +214,6 @@ impl From<BdkEsploraError> for EsploraError {
} }
} }
impl std::error::Error for EsploraError {}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::error::EsploraError; use crate::error::EsploraError;
@ -290,7 +238,7 @@ mod test {
let error = CalculateFeeError::MissingTxOut { out_points }; let error = CalculateFeeError::MissingTxOut { out_points };
let expected_message: String = format!( let expected_message: String = format!(
"Missing transaction output: [{:?}, {:?}]", "missing transaction output: [{:?}, {:?}]",
OutPoint { OutPoint {
txid: "0000000000000000000000000000000000000000000000000000000000000001" txid: "0000000000000000000000000000000000000000000000000000000000000001"
.to_string(), .to_string(),
@ -310,7 +258,7 @@ mod test {
fn test_error_negative_fee() { fn test_error_negative_fee() {
let error = CalculateFeeError::NegativeFee { fee: -100 }; let error = CalculateFeeError::NegativeFee { fee: -100 };
assert_eq!(error.to_string(), "Negative fee value: -100"); assert_eq!(error.to_string(), "negative fee value: -100");
} }
#[test] #[test]
@ -320,49 +268,49 @@ mod test {
EsploraError::Ureq { EsploraError::Ureq {
error_message: "Network error".to_string(), error_message: "Network error".to_string(),
}, },
"Ureq error: Network error", "ureq error: Network error",
), ),
( (
EsploraError::UreqTransport { EsploraError::UreqTransport {
error_message: "Timeout occurred".to_string(), error_message: "Timeout occurred".to_string(),
}, },
"Ureq transport error: Timeout occurred", "ureq transport error: Timeout occurred",
), ),
( (
EsploraError::Http { status_code: 404 }, EsploraError::Http { status_code: 404 },
"HTTP error with status code: 404", "http error with status code: 404",
), ),
( (
EsploraError::Io { EsploraError::Io {
error_message: "File not found".to_string(), error_message: "File not found".to_string(),
}, },
"IO error: File not found", "io error: File not found",
), ),
(EsploraError::NoHeader, "No header found in the response"), (EsploraError::NoHeader, "no header found in the response"),
( (
EsploraError::Parsing { EsploraError::Parsing {
error_message: "Invalid JSON".to_string(), error_message: "Invalid JSON".to_string(),
}, },
"Parsing error: Invalid JSON", "parsing error: Invalid JSON",
), ),
( (
EsploraError::BitcoinEncoding { EsploraError::BitcoinEncoding {
error_message: "Bad format".to_string(), error_message: "Bad format".to_string(),
}, },
"Bitcoin encoding error: Bad format", "bitcoin encoding error: Bad format",
), ),
( (
EsploraError::Hex { EsploraError::Hex {
error_message: "Invalid hex".to_string(), error_message: "Invalid hex".to_string(),
}, },
"Hex decoding error: Invalid hex", "hex decoding error: Invalid hex",
), ),
(EsploraError::TransactionNotFound, "Transaction not found"), (EsploraError::TransactionNotFound, "transaction not found"),
( (
EsploraError::HeaderHeightNotFound { height: 123456 }, EsploraError::HeaderHeightNotFound { height: 123456 },
"Header height 123456 not found", "header height 123456 not found",
), ),
(EsploraError::HeaderHashNotFound, "Header hash not found"), (EsploraError::HeaderHashNotFound, "header hash not found"),
]; ];
for (error, expected_message) in cases { for (error, expected_message) in cases {