Skip to content

Commit

Permalink
feat: add esplora error
Browse files Browse the repository at this point in the history
  • Loading branch information
reez committed Feb 9, 2024
1 parent 50f102b commit 9fa0901
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 5 deletions.
18 changes: 17 additions & 1 deletion bdk-ffi/src/bdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ interface CalculateFeeError {
NegativeFee(i64 fee);
};

[Error]
interface EsploraError {
Ureq(string error_message);
UreqTransport(string error_message);
Http(u16 status_code);
Io(string error_message);
NoHeader();
Parsing(string error_message);
BitcoinEncoding(string error_message);
Hex(string error_message);
TransactionNotFound();
HeaderHeightNotFound(u32 height);
HeaderHashNotFound();
};


// ------------------------------------------------------------------------
// bdk crate - types module
// ------------------------------------------------------------------------
Expand Down Expand Up @@ -261,7 +277,7 @@ interface Descriptor {
interface EsploraClient {
constructor(string url);

[Throws=Alpha3Error]
[Throws=EsploraError]
Update full_scan(Wallet wallet, u64 stop_gap, u64 parallel_requests);

[Throws=Alpha3Error]
Expand Down
138 changes: 138 additions & 0 deletions bdk-ffi/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::bitcoin::OutPoint;

use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError;
use bdk_esplora::esplora_client::Error as BdkEsploraError;

use std::fmt;

Expand Down Expand Up @@ -103,8 +104,88 @@ 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 {
fn from(error: BdkEsploraError) -> Self {
match error {
BdkEsploraError::Ureq(e) => EsploraError::Ureq {
error_message: e.to_string(),
},
BdkEsploraError::UreqTransport(e) => EsploraError::UreqTransport {
error_message: e.to_string(),
},
BdkEsploraError::HttpResponse(code) => EsploraError::Http { status_code: code },
BdkEsploraError::Io(e) => EsploraError::Io {
error_message: e.to_string(),
},
BdkEsploraError::NoHeader => EsploraError::NoHeader,
BdkEsploraError::Parsing(e) => EsploraError::Parsing {
error_message: e.to_string(),
},
BdkEsploraError::BitcoinEncoding(e) => EsploraError::BitcoinEncoding {
error_message: e.to_string(),
},
BdkEsploraError::Hex(e) => EsploraError::Hex {
error_message: e.to_string(),
},
BdkEsploraError::TransactionNotFound(_) => EsploraError::TransactionNotFound,
BdkEsploraError::HeaderHeightNotFound(height) => {
EsploraError::HeaderHeightNotFound { height }
}
BdkEsploraError::HeaderHashNotFound(_) => EsploraError::HeaderHashNotFound,
}
}
}

impl std::error::Error for EsploraError {}

#[cfg(test)]
mod test {
use crate::error::EsploraError;
use crate::CalculateFeeError;
use crate::OutPoint;

Expand Down Expand Up @@ -148,4 +229,61 @@ mod test {

assert_eq!(error.to_string(), "Negative fee value: -100");
}

#[test]
fn test_esplora_errors() {
let cases = vec![
(
EsploraError::Ureq {
error_message: "Network error".to_string(),
},
"Ureq error: Network error",
),
(
EsploraError::UreqTransport {
error_message: "Timeout occurred".to_string(),
},
"Ureq transport error: Timeout occurred",
),
(
EsploraError::Http { status_code: 404 },
"HTTP error with status code: 404",
),
(
EsploraError::Io {
error_message: "File not found".to_string(),
},
"IO error: File not found",
),
(EsploraError::NoHeader, "No header found in the response"),
(
EsploraError::Parsing {
error_message: "Invalid JSON".to_string(),
},
"Parsing error: Invalid JSON",
),
(
EsploraError::BitcoinEncoding {
error_message: "Bad format".to_string(),
},
"Bitcoin encoding error: Bad format",
),
(
EsploraError::Hex {
error_message: "Invalid hex".to_string(),
},
"Hex decoding error: Invalid hex",
),
(EsploraError::TransactionNotFound, "Transaction not found"),
(
EsploraError::HeaderHeightNotFound { height: 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);
}
}
}
8 changes: 4 additions & 4 deletions bdk-ffi/src/esplora.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::Alpha3Error;
use crate::error::{Alpha3Error, EsploraError};
use crate::wallet::{Update, Wallet};

use bdk::bitcoin::Transaction as BdkTransaction;
Expand All @@ -24,7 +24,7 @@ impl EsploraClient {
wallet: Arc<Wallet>,
stop_gap: u64,
parallel_requests: u64,
) -> Result<Arc<Update>, Alpha3Error> {
) -> Result<Arc<Update>, EsploraError> {
let wallet = wallet.get_wallet();

let previous_tip = wallet.latest_checkpoint();
Expand All @@ -33,13 +33,13 @@ impl EsploraClient {
let (update_graph, last_active_indices) = self
.0
.full_scan(keychain_spks, stop_gap as usize, parallel_requests as usize)
.unwrap();
.map_err(EsploraError::from)?;

let missing_heights = update_graph.missing_heights(wallet.local_chain());
let chain_update = self
.0
.update_local_chain(previous_tip, missing_heights)
.unwrap();
.map_err(EsploraError::from)?;

let update = BdkUpdate {
last_active_indices,
Expand Down
1 change: 1 addition & 0 deletions bdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::bitcoin::TxOut;
use crate::descriptor::Descriptor;
use crate::error::Alpha3Error;
use crate::error::CalculateFeeError;
use crate::error::EsploraError;
use crate::esplora::EsploraClient;
use crate::keys::DerivationPath;
use crate::keys::DescriptorPublicKey;
Expand Down

0 comments on commit 9fa0901

Please sign in to comment.