From 70ef5b53018fe2f7062925e4cf14afed87594f89 Mon Sep 17 00:00:00 2001 From: Matthew Date: Thu, 8 Feb 2024 12:10:24 -0600 Subject: [PATCH] feat: add esplora error --- bdk-ffi/src/error.rs | 112 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index d19fcebd..b00200f5 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -1,8 +1,10 @@ use crate::bitcoin::OutPoint; use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; +use bdk_esplora::esplora_client::Error as BdkEsploraError; use std::fmt; +use std::io; use bdk::descriptor::DescriptorError; use bdk::wallet::error::{BuildFeeBumpError, CreateTxError}; @@ -103,10 +105,75 @@ impl From for CalculateFeeError { impl std::error::Error for CalculateFeeError {} +#[derive(Debug)] +pub enum EsploraError { + Ureq(String), + UreqTransport(String), + Http(u16), + Io(io::Error), + NoHeader, + Parsing(io::Error), + BitcoinEncoding(io::Error), + Hex(io::Error), + TransactionNotFound, + HeaderHeightNotFound(u32), + HeaderHashNotFound, +} + +impl fmt::Display for EsploraError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EsploraError::Ureq(message) => write!(f, "Ureq error: {}", message), + EsploraError::UreqTransport(message) => write!(f, "Ureq transport error: {}", message), + EsploraError::Http(code) => write!(f, "HTTP error with status code: {}", code), + EsploraError::Io(err) => write!(f, "IO error: {}", err), + EsploraError::NoHeader => write!(f, "No header found in the response"), + EsploraError::Parsing(err) => write!(f, "Parsing error: {}", err), + EsploraError::BitcoinEncoding(err) => write!(f, "Bitcoin encoding error: {}", err), + EsploraError::Hex(err) => write!(f, "Hex decoding error: {}", err), + 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 { + BdkEsploraError::Ureq(e) => EsploraError::Ureq(e.to_string()), + BdkEsploraError::UreqTransport(_) => { + EsploraError::UreqTransport("Ureq transport error".to_string()) + } + BdkEsploraError::HttpResponse(code) => EsploraError::Http(code), + BdkEsploraError::Io(e) => EsploraError::Io(e), + BdkEsploraError::NoHeader => EsploraError::NoHeader, + BdkEsploraError::Parsing(e) => { + EsploraError::Parsing(io::Error::new(io::ErrorKind::Other, e.to_string())) + } + BdkEsploraError::BitcoinEncoding(e) => { + EsploraError::BitcoinEncoding(io::Error::new(io::ErrorKind::Other, e.to_string())) + } + BdkEsploraError::Hex(e) => { + EsploraError::Hex(io::Error::new(io::ErrorKind::Other, e.to_string())) + } + BdkEsploraError::TransactionNotFound(_) => EsploraError::TransactionNotFound, + BdkEsploraError::HeaderHeightNotFound(height) => { + EsploraError::HeaderHeightNotFound(height) + } + BdkEsploraError::HeaderHashNotFound(_) => EsploraError::HeaderHashNotFound, + } + } +} + #[cfg(test)] mod test { + use crate::error::EsploraError; use crate::CalculateFeeError; use crate::OutPoint; + use std::io; #[test] fn test_error_missing_tx_out() { @@ -148,4 +215,49 @@ mod test { assert_eq!(error.to_string(), "Negative fee value: -100"); } + + #[test] + fn test_esplora_errors() { + let cases = vec![ + ( + EsploraError::Ureq("Network error".to_string()), + "Ureq error: Network error", + ), + ( + EsploraError::UreqTransport("Timeout occurred".to_string()), + "Ureq transport error: Timeout occurred", + ), + (EsploraError::Http(404), "HTTP error with status code: 404"), + ( + EsploraError::Io(io::Error::new(io::ErrorKind::NotFound, "File not found")), + "IO error: File not found", + ), + (EsploraError::NoHeader, "No header found in the response"), + ( + EsploraError::Parsing(io::Error::new(io::ErrorKind::InvalidData, "Invalid JSON")), + "Parsing error: Invalid JSON", + ), + ( + EsploraError::BitcoinEncoding(io::Error::new( + io::ErrorKind::InvalidInput, + "Bad format", + )), + "Bitcoin encoding error: Bad format", + ), + ( + EsploraError::Hex(io::Error::new(io::ErrorKind::InvalidData, "Invalid hex")), + "Hex decoding error: Invalid hex", + ), + (EsploraError::TransactionNotFound, "Transaction not found"), + ( + EsploraError::HeaderHeightNotFound(123456), + "Header height 123456 not found", + ), + (EsploraError::HeaderHashNotFound, "Header hash not found"), + ]; + + for (error, expected_message) in cases { + assert_eq!(error.to_string(), expected_message); + } + } }