Skip to content

Commit

Permalink
refactor: streamline blockchain clients error names
Browse files Browse the repository at this point in the history
  • Loading branch information
thunderbiscuit committed May 16, 2024
1 parent 8f4c80c commit ca8a3d0
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 51 deletions.
10 changes: 5 additions & 5 deletions bdk-ffi/src/bdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ interface DescriptorKeyError {
};

[Error]
interface ElectrumClientError {
interface ElectrumError {
IOError(string error_message);
Json(string error_message);
Hex(string error_message);
Expand Down Expand Up @@ -493,16 +493,16 @@ interface EsploraClient {
// ------------------------------------------------------------------------

interface ElectrumClient {
[Throws=ElectrumClientError]
[Throws=ElectrumError]
constructor(string url);

[Throws=ElectrumClientError]
[Throws=ElectrumError]
Update full_scan(FullScanRequest full_scan_request, u64 stop_gap, u64 batch_size, boolean fetch_prev_txouts);

[Throws=ElectrumClientError]
[Throws=ElectrumError]
Update sync(SyncRequest sync_request, u64 batch_size, boolean fetch_prev_txouts);

[Throws=ElectrumClientError]
[Throws=ElectrumError]
string broadcast([ByRef] Transaction transaction);
};

Expand Down
20 changes: 10 additions & 10 deletions bdk-ffi/src/electrum.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::ElectrumClientError;
use crate::bitcoin::Transaction;
use crate::error::ElectrumError;
use crate::types::{FullScanRequest, SyncRequest};
use crate::wallet::Update;
use std::collections::BTreeMap;

use bdk::bitcoin::Transaction as BdkTransaction;
use bdk::chain::spk_client::FullScanRequest as BdkFullScanRequest;
Expand All @@ -12,13 +12,13 @@ use bdk::KeychainKind;
use bdk_electrum::electrum_client::{Client as BdkBlockingClient, ElectrumApi};
use bdk_electrum::{ElectrumExt, ElectrumFullScanResult, ElectrumSyncResult};

use crate::bitcoin::Transaction;
use std::collections::BTreeMap;
use std::sync::Arc;

pub struct ElectrumClient(BdkBlockingClient);

impl ElectrumClient {
pub fn new(url: String) -> Result<Self, ElectrumClientError> {
pub fn new(url: String) -> Result<Self, ElectrumError> {
let client = BdkBlockingClient::new(url.as_str())?;
Ok(Self(client))
}
Expand All @@ -29,14 +29,14 @@ impl ElectrumClient {
stop_gap: u64,
batch_size: u64,
fetch_prev_txouts: bool,
) -> Result<Arc<Update>, ElectrumClientError> {
) -> Result<Arc<Update>, ElectrumError> {
// using option and take is not ideal but the only way to take full ownership of the request
let request: BdkFullScanRequest<KeychainKind> = request
.0
.lock()
.unwrap()
.take()
.ok_or(ElectrumClientError::RequestAlreadyConsumed)?;
.ok_or(ElectrumError::RequestAlreadyConsumed)?;

let electrum_result: ElectrumFullScanResult<KeychainKind> = self.0.full_scan(
request,
Expand All @@ -61,14 +61,14 @@ impl ElectrumClient {
request: Arc<SyncRequest>,
batch_size: u64,
fetch_prev_txouts: bool,
) -> Result<Arc<Update>, ElectrumClientError> {
) -> Result<Arc<Update>, ElectrumError> {
// using option and take is not ideal but the only way to take full ownership of the request
let request: BdkSyncRequest = request
.0
.lock()
.unwrap()
.take()
.ok_or(ElectrumClientError::RequestAlreadyConsumed)?;
.ok_or(ElectrumError::RequestAlreadyConsumed)?;

let electrum_result: ElectrumSyncResult =
self.0
Expand All @@ -85,11 +85,11 @@ impl ElectrumClient {
Ok(Arc::new(Update(update)))
}

pub fn broadcast(&self, transaction: &Transaction) -> Result<String, ElectrumClientError> {
pub fn broadcast(&self, transaction: &Transaction) -> Result<String, ElectrumError> {
let bdk_transaction: BdkTransaction = transaction.into();
self.0
.transaction_broadcast(&bdk_transaction)
.map_err(ElectrumClientError::from)
.map_err(ElectrumError::from)
.map(|txid| txid.to_string())
}
}
70 changes: 35 additions & 35 deletions bdk-ffi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ pub enum DescriptorKeyError {
}

#[derive(Debug, thiserror::Error)]
pub enum ElectrumClientError {
pub enum ElectrumError {
#[error("{error_message}")]
IOError { error_message: String },

Expand Down Expand Up @@ -558,44 +558,44 @@ impl From<BdkAddressError> for AddressError {
}
}

impl From<BdkElectrumError> for ElectrumClientError {
impl From<BdkElectrumError> for ElectrumError {
fn from(error: BdkElectrumError) -> Self {
match error {
BdkElectrumError::IOError(e) => ElectrumClientError::IOError {
BdkElectrumError::IOError(e) => ElectrumError::IOError {
error_message: e.to_string(),
},
BdkElectrumError::JSON(e) => ElectrumClientError::Json {
BdkElectrumError::JSON(e) => ElectrumError::Json {
error_message: e.to_string(),
},
BdkElectrumError::Hex(e) => ElectrumClientError::Hex {
BdkElectrumError::Hex(e) => ElectrumError::Hex {
error_message: e.to_string(),
},
BdkElectrumError::Protocol(e) => ElectrumClientError::Protocol {
BdkElectrumError::Protocol(e) => ElectrumError::Protocol {
error_message: e.to_string(),
},
BdkElectrumError::Bitcoin(e) => ElectrumClientError::Bitcoin {
BdkElectrumError::Bitcoin(e) => ElectrumError::Bitcoin {
error_message: e.to_string(),
},
BdkElectrumError::AlreadySubscribed(_) => ElectrumClientError::AlreadySubscribed,
BdkElectrumError::NotSubscribed(_) => ElectrumClientError::NotSubscribed,
BdkElectrumError::InvalidResponse(e) => ElectrumClientError::InvalidResponse {
BdkElectrumError::AlreadySubscribed(_) => ElectrumError::AlreadySubscribed,
BdkElectrumError::NotSubscribed(_) => ElectrumError::NotSubscribed,
BdkElectrumError::InvalidResponse(e) => ElectrumError::InvalidResponse {
error_message: e.to_string(),
},
BdkElectrumError::Message(e) => ElectrumClientError::Message {
BdkElectrumError::Message(e) => ElectrumError::Message {
error_message: e.to_string(),
},
BdkElectrumError::InvalidDNSNameError(domain) => {
ElectrumClientError::InvalidDNSNameError { domain }
ElectrumError::InvalidDNSNameError { domain }
}
BdkElectrumError::MissingDomain => ElectrumClientError::MissingDomain,
BdkElectrumError::AllAttemptsErrored(_) => ElectrumClientError::AllAttemptsErrored,
BdkElectrumError::SharedIOError(e) => ElectrumClientError::SharedIOError {
BdkElectrumError::MissingDomain => ElectrumError::MissingDomain,
BdkElectrumError::AllAttemptsErrored(_) => ElectrumError::AllAttemptsErrored,
BdkElectrumError::SharedIOError(e) => ElectrumError::SharedIOError {
error_message: e.to_string(),
},
BdkElectrumError::CouldntLockReader => ElectrumClientError::CouldntLockReader,
BdkElectrumError::Mpsc => ElectrumClientError::Mpsc,
BdkElectrumError::CouldntLockReader => ElectrumError::CouldntLockReader,
BdkElectrumError::Mpsc => ElectrumError::Mpsc,
BdkElectrumError::CouldNotCreateConnection(error_message) => {
ElectrumClientError::CouldNotCreateConnection {
ElectrumError::CouldNotCreateConnection {
error_message: error_message.to_string(),
}
}
Expand Down Expand Up @@ -1079,7 +1079,7 @@ impl From<NewOrLoadError> for WalletCreationError {
mod test {
use crate::error::{
AddressError, Bip32Error, Bip39Error, CannotConnectError, CreateTxError, DescriptorError,
DescriptorKeyError, ElectrumClientError, EsploraError, ExtractTxError, FeeRateError,
DescriptorKeyError, ElectrumError, EsploraError, ExtractTxError, FeeRateError,
ParseAmountError, PersistenceError, PsbtParseError, TransactionError, TxidParseError,
WalletCreationError,
};
Expand Down Expand Up @@ -1488,77 +1488,77 @@ mod test {
fn test_error_electrum_client() {
let cases = vec![
(
ElectrumClientError::IOError { error_message: "message".to_string(), },
ElectrumError::IOError { error_message: "message".to_string(), },
"message",
),
(
ElectrumClientError::Json { error_message: "message".to_string(), },
ElectrumError::Json { error_message: "message".to_string(), },
"message",
),
(
ElectrumClientError::Hex { error_message: "message".to_string(), },
ElectrumError::Hex { error_message: "message".to_string(), },
"message",
),
(
ElectrumClientError::Protocol { error_message: "message".to_string(), },
ElectrumError::Protocol { error_message: "message".to_string(), },
"electrum server error: message",
),
(
ElectrumClientError::Bitcoin {
ElectrumError::Bitcoin {
error_message: "message".to_string(),
},
"message",
),
(
ElectrumClientError::AlreadySubscribed,
ElectrumError::AlreadySubscribed,
"already subscribed to the notifications of an address",
),
(
ElectrumClientError::NotSubscribed,
ElectrumError::NotSubscribed,
"not subscribed to the notifications of an address",
),
(
ElectrumClientError::InvalidResponse {
ElectrumError::InvalidResponse {
error_message: "message".to_string(),
},
"error during the deserialization of a response from the server: message",
),
(
ElectrumClientError::Message {
ElectrumError::Message {
error_message: "message".to_string(),
},
"message",
),
(
ElectrumClientError::InvalidDNSNameError {
ElectrumError::InvalidDNSNameError {
domain: "domain".to_string(),
},
"invalid domain name domain not matching SSL certificate",
),
(
ElectrumClientError::MissingDomain,
ElectrumError::MissingDomain,
"missing domain while it was explicitly asked to validate it",
),
(
ElectrumClientError::AllAttemptsErrored,
ElectrumError::AllAttemptsErrored,
"made one or multiple attempts, all errored",
),
(
ElectrumClientError::SharedIOError {
ElectrumError::SharedIOError {
error_message: "message".to_string(),
},
"message",
),
(
ElectrumClientError::CouldntLockReader,
ElectrumError::CouldntLockReader,
"couldn't take a lock on the reader mutex. This means that there's already another reader thread is running"
),
(
ElectrumClientError::Mpsc,
ElectrumError::Mpsc,
"broken IPC communication channel: the other thread probably has exited",
),
(
ElectrumClientError::CouldNotCreateConnection {
ElectrumError::CouldNotCreateConnection {
error_message: "message".to_string(),
},
"message",
Expand Down
2 changes: 1 addition & 1 deletion bdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::error::CannotConnectError;
use crate::error::CreateTxError;
use crate::error::DescriptorError;
use crate::error::DescriptorKeyError;
use crate::error::ElectrumClientError;
use crate::error::ElectrumError;
use crate::error::EsploraError;
use crate::error::ExtractTxError;
use crate::error::FeeRateError;
Expand Down
44 changes: 44 additions & 0 deletions bdk-swift/Tests/BitcoinDevKitTests/LiveElectrumClientTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import XCTest
@testable import BitcoinDevKit

private let SIGNET_ELECTRUM_URL = "ssl://mempool.space:60602"

final class LiveElectrumClientTests: XCTestCase {
func testSyncedBalance() throws {
let descriptor = try Descriptor(
descriptor: "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)",
network: Network.signet
)
let wallet = try Wallet.newNoPersist(
descriptor: descriptor,
changeDescriptor: nil,
network: .signet
)
let electrumClient: ElectrumClient = try ElectrumClient(url: SIGNET_ELECTRUM_URL)
let fullScanRequest: FullScanRequest = wallet.startFullScan()
let update = try electrumClient.fullScan(
fullScanRequest: fullScanRequest,
stopGap: 10,
batchSize: 10,
fetchPrevTxouts: false
)
try wallet.applyUpdate(update: update)
let _ = try wallet.commit()
let address = try wallet.revealNextAddress(keychain: KeychainKind.external).address.asString()

XCTAssertGreaterThan(
wallet.getBalance().total.toSat(),
UInt64(0),
"Wallet must have positive balance, please send funds to \(address)"
)

print("Transactions count: \(wallet.transactions().count)")
let transactions = wallet.transactions().prefix(3)
for tx in transactions {
let sentAndReceived = wallet.sentAndReceived(tx: tx.transaction)
print("Transaction: \(tx.transaction.txid())")
print("Sent \(sentAndReceived.sent)")
print("Received \(sentAndReceived.received)")
}
}
}

0 comments on commit ca8a3d0

Please sign in to comment.