diff --git a/bdk-ffi/Cargo.lock b/bdk-ffi/Cargo.lock index 45660b3..660bf9e 100644 --- a/bdk-ffi/Cargo.lock +++ b/bdk-ffi/Cargo.lock @@ -161,6 +161,7 @@ dependencies = [ "bdk", "bdk_esplora", "bdk_file_store", + "thiserror", "uniffi", ] @@ -883,18 +884,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/bdk-ffi/Cargo.toml b/bdk-ffi/Cargo.toml index 70e32c6..6fbe564 100644 --- a/bdk-ffi/Cargo.toml +++ b/bdk-ffi/Cargo.toml @@ -24,6 +24,7 @@ bdk_esplora = { version = "0.9.0", default-features = false, features = ["std", bdk_file_store = { version = "0.7.0" } uniffi = { version = "=0.26.1" } +thiserror = "1.0.58" [build-dependencies] uniffi = { version = "=0.26.1", features = ["build"] } diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index 756ed98..cb3c0c0 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -3,8 +3,6 @@ use crate::bitcoin::OutPoint; use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; use bdk_esplora::esplora_client::Error as BdkEsploraError; -use std::fmt; - use bdk::bitcoin::Network; use bdk::descriptor::DescriptorError; use bdk::wallet::error::{BuildFeeBumpError, CreateTxError}; @@ -14,77 +12,93 @@ use bdk_file_store::FileError as BdkFileError; use bdk_file_store::IterError; use std::convert::Infallible; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Alpha3Error { + #[error("generic error in ffi")] Generic, } -impl fmt::Display for Alpha3Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Alpha3Error::Generic => write!(f, "Error in FFI"), - } - } +#[derive(Debug, thiserror::Error)] +pub enum CalculateFeeError { + #[error("missing transaction output: {out_points:?}")] + MissingTxOut { out_points: Vec }, + + #[error("negative fee value: {fee}")] + NegativeFee { fee: i64 }, } -impl std::error::Error for Alpha3Error {} - -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum WalletCreationError { // Errors coming from the FileError enum - Io { - e: String, - }, - InvalidMagicBytes { - got: Vec, - expected: Vec, - }, + #[error("io error trying to read file: {e}")] + Io { e: String }, + + #[error("file has invalid magic bytes: expected={expected:?} got={got:?}")] + InvalidMagicBytes { got: Vec, expected: Vec }, // Errors coming from the NewOrLoadError enum + #[error("error with descriptor")] Descriptor, + + #[error("failed to write to persistence")] Write, + + #[error("failed to load from persistence")] Load, + + #[error("wallet is not initialized, persistence backend is empty")] NotInitialized, + + #[error("loaded genesis hash does not match the expected one")] LoadedGenesisDoesNotMatch, + + #[error("loaded network type is not {expected}, got {got:?}")] LoadedNetworkDoesNotMatch { expected: Network, got: Option, }, } -impl fmt::Display for WalletCreationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Io { e } => write!(f, "io error trying to read file: {}", e), - 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) - } - } - } -} +#[derive(Debug, thiserror::Error)] +pub enum EsploraError { + #[error("ureq error: {error_message}")] + Ureq { error_message: String }, -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 for WalletCreationError { fn from(error: BdkFileError) -> Self { match error { - BdkFileError::Io(_) => WalletCreationError::Io { - e: "io error trying to read file".to_string(), - }, + BdkFileError::Io(e) => WalletCreationError::Io { e: e.to_string() }, BdkFileError::InvalidMagicBytes { got, expected } => { WalletCreationError::InvalidMagicBytes { got, expected } } @@ -157,23 +171,6 @@ impl From> for Alpha3Error { } } -#[derive(Debug)] -pub enum CalculateFeeError { - MissingTxOut { out_points: Vec }, - 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 for CalculateFeeError { fn from(error: BdkCalculateFeeError) -> Self { match error { @@ -185,53 +182,6 @@ impl From 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 for EsploraError { fn from(error: BdkEsploraError) -> Self { match error { @@ -264,8 +214,6 @@ impl From for EsploraError { } } -impl std::error::Error for EsploraError {} - #[cfg(test)] mod test { use crate::error::EsploraError; @@ -290,7 +238,7 @@ mod test { let error = CalculateFeeError::MissingTxOut { out_points }; let expected_message: String = format!( - "Missing transaction output: [{:?}, {:?}]", + "missing transaction output: [{:?}, {:?}]", OutPoint { txid: "0000000000000000000000000000000000000000000000000000000000000001" .to_string(), @@ -310,7 +258,7 @@ mod test { fn test_error_negative_fee() { 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] @@ -320,49 +268,49 @@ mod test { EsploraError::Ureq { error_message: "Network error".to_string(), }, - "Ureq error: Network error", + "ureq error: Network error", ), ( EsploraError::UreqTransport { error_message: "Timeout occurred".to_string(), }, - "Ureq transport error: Timeout occurred", + "ureq transport error: Timeout occurred", ), ( EsploraError::Http { status_code: 404 }, - "HTTP error with status code: 404", + "http error with status code: 404", ), ( EsploraError::Io { 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 { error_message: "Invalid JSON".to_string(), }, - "Parsing error: Invalid JSON", + "parsing error: Invalid JSON", ), ( EsploraError::BitcoinEncoding { error_message: "Bad format".to_string(), }, - "Bitcoin encoding error: Bad format", + "bitcoin encoding error: Bad format", ), ( EsploraError::Hex { 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 }, - "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 {