Skip to content

Commit 242f111

Browse files
committed
refacor(wallet)!: Remove catch-all bdk::error::Error and replace with per function error enums
Add AddUtxoError and use as error type for TxBuilder::add_utxo Add AddForeignUtxoError and use as error type for Wallet::add_utxo() and Wallet::add_utxos() Add AllowShrinkingError and use as error type for TxBuilder::allow_shrinking
1 parent 59d829e commit 242f111

File tree

8 files changed

+149
-129
lines changed

8 files changed

+149
-129
lines changed

crates/bdk/examples/mnemonic_to_descriptors.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// You may not use this file except in accordance with one or both of these
77
// licenses.
88

9+
use anyhow::anyhow;
910
use bdk::bitcoin::bip32::DerivationPath;
1011
use bdk::bitcoin::secp256k1::Secp256k1;
1112
use bdk::bitcoin::Network;
@@ -14,21 +15,19 @@ use bdk::descriptor::IntoWalletDescriptor;
1415
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
1516
use bdk::keys::{GeneratableKey, GeneratedKey};
1617
use bdk::miniscript::Tap;
17-
use bdk::Error as BDK_Error;
18-
use std::error::Error;
1918
use std::str::FromStr;
2019

2120
/// This example demonstrates how to generate a mnemonic phrase
2221
/// using BDK and use that to generate a descriptor string.
23-
fn main() -> Result<(), Box<dyn Error>> {
22+
fn main() -> Result<(), anyhow::Error> {
2423
let secp = Secp256k1::new();
2524

2625
// In this example we are generating a 12 words mnemonic phrase
2726
// but it is also possible generate 15, 18, 21 and 24 words
2827
// using their respective `WordCount` variant.
2928
let mnemonic: GeneratedKey<_, Tap> =
3029
Mnemonic::generate((WordCount::Words12, Language::English))
31-
.map_err(|_| BDK_Error::Generic("Mnemonic generation error".to_string()))?;
30+
.map_err(|_| anyhow!("Mnemonic generation error"))?;
3231

3332
println!("Mnemonic phrase: {}", *mnemonic);
3433
let mnemonic_with_passphrase = (mnemonic, None);

crates/bdk/src/descriptor/policy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
//! let signers = Arc::new(SignersContainer::build(key_map, &extended_desc, &secp));
3434
//! let policy = extended_desc.extract_policy(&signers, BuildSatisfaction::None, &secp)?;
3535
//! println!("policy: {}", serde_json::to_string(&policy).unwrap());
36-
//! # Ok::<(), bdk::Error>(())
36+
//! # Ok::<(), anyhow::Error>(())
3737
//! ```
3838
3939
use crate::collections::{BTreeMap, HashSet, VecDeque};

crates/bdk/src/error.rs

Lines changed: 104 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,9 @@ use crate::descriptor::DescriptorError;
1616
use crate::wallet::coin_selection;
1717
use crate::{descriptor, wallet, FeeRate, KeychainKind};
1818
use alloc::string::String;
19-
use bitcoin::{absolute, psbt, OutPoint, Sequence, Txid};
19+
use bitcoin::{absolute, psbt, OutPoint, ScriptBuf, Sequence, Txid};
2020
use core::fmt;
2121

22-
/// Old catch-all errors enum that can be thrown by the [`Wallet`](crate::wallet::Wallet)
23-
#[derive(Debug)]
24-
pub enum Error {
25-
/// Generic error
26-
Generic(String),
27-
/// Happens when trying to spend an UTXO that is not in the internal database
28-
UnknownUtxo,
29-
/// Node doesn't have data to estimate a fee rate
30-
FeeRateUnavailable,
31-
/// Error while working with [`keys`](crate::keys)
32-
Key(crate::keys::KeyError),
33-
/// Descriptor checksum mismatch
34-
ChecksumMismatch,
35-
/// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
36-
InvalidOutpoint(OutPoint),
37-
/// Error related to the parsing and usage of descriptors
38-
Descriptor(crate::descriptor::error::Error),
39-
/// Miniscript error
40-
Miniscript(miniscript::Error),
41-
/// BIP32 error
42-
Bip32(bitcoin::bip32::Error),
43-
}
44-
4522
/// Errors returned by miniscript when updating inconsistent PSBTs
4623
#[derive(Debug, Clone)]
4724
pub enum MiniscriptPsbtError {
@@ -66,30 +43,6 @@ impl fmt::Display for MiniscriptPsbtError {
6643
#[cfg(feature = "std")]
6744
impl std::error::Error for MiniscriptPsbtError {}
6845

69-
#[cfg(feature = "std")]
70-
impl fmt::Display for Error {
71-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72-
match self {
73-
Self::Generic(err) => write!(f, "Generic error: {}", err),
74-
Self::UnknownUtxo => write!(f, "UTXO not found in the internal database"),
75-
Self::FeeRateUnavailable => write!(f, "Fee rate unavailable"),
76-
Self::Key(err) => write!(f, "Key error: {}", err),
77-
Self::ChecksumMismatch => write!(f, "Descriptor checksum mismatch"),
78-
Self::InvalidOutpoint(outpoint) => write!(
79-
f,
80-
"Requested outpoint doesn't exist in the tx: {}",
81-
outpoint
82-
),
83-
Self::Descriptor(err) => write!(f, "Descriptor error: {}", err),
84-
Self::Miniscript(err) => write!(f, "Miniscript error: {}", err),
85-
Self::Bip32(err) => write!(f, "BIP32 error: {}", err),
86-
}
87-
}
88-
}
89-
90-
#[cfg(feature = "std")]
91-
impl std::error::Error for Error {}
92-
9346
macro_rules! impl_error {
9447
( $from:ty, $to:ident ) => {
9548
impl_error!($from, $to, Error);
@@ -103,22 +56,6 @@ macro_rules! impl_error {
10356
};
10457
}
10558

106-
impl_error!(descriptor::error::Error, Descriptor);
107-
108-
impl From<crate::keys::KeyError> for Error {
109-
fn from(key_error: crate::keys::KeyError) -> Error {
110-
match key_error {
111-
crate::keys::KeyError::Miniscript(inner) => Error::Miniscript(inner),
112-
crate::keys::KeyError::Bip32(inner) => Error::Bip32(inner),
113-
crate::keys::KeyError::InvalidChecksum => Error::ChecksumMismatch,
114-
e => Error::Key(e),
115-
}
116-
}
117-
}
118-
119-
impl_error!(miniscript::Error, Miniscript);
120-
impl_error!(bitcoin::bip32::Error, Bip32);
121-
12259
#[derive(Debug)]
12360
/// Error returned from [`TxBuilder::finish`]
12461
///
@@ -330,25 +267,13 @@ impl<P: core::fmt::Display + core::fmt::Debug> std::error::Error for CreateTxErr
330267
/// [`Wallet::build_fee_bump`]: wallet::Wallet::build_fee_bump
331268
pub enum BuildFeeBumpError {
332269
/// Happens when trying to spend an UTXO that is not in the internal database
333-
UnknownUtxo {
334-
/// The outpoint of the missing UTXO
335-
outpoint: OutPoint,
336-
},
270+
UnknownUtxo(OutPoint),
337271
/// Thrown when a tx is not found in the internal database
338-
TransactionNotFound {
339-
/// The txid of the missing transaction
340-
txid: Txid,
341-
},
272+
TransactionNotFound(Txid),
342273
/// Happens when trying to bump a transaction that is already confirmed
343-
TransactionConfirmed {
344-
/// The txid of the already confirmed transaction
345-
txid: Txid,
346-
},
274+
TransactionConfirmed(Txid),
347275
/// Trying to replace a tx that has a sequence >= `0xFFFFFFFE`
348-
IrreplaceableTransaction {
349-
/// The txid of the irreplaceable transaction
350-
txid: Txid,
351-
},
276+
IrreplaceableTransaction(Txid),
352277
/// Node doesn't have data to estimate a fee rate
353278
FeeRateUnavailable,
354279
}
@@ -357,22 +282,22 @@ pub enum BuildFeeBumpError {
357282
impl fmt::Display for BuildFeeBumpError {
358283
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359284
match self {
360-
Self::UnknownUtxo { outpoint } => write!(
285+
Self::UnknownUtxo(outpoint) => write!(
361286
f,
362287
"UTXO not found in the internal database with txid: {}, vout: {}",
363288
outpoint.txid, outpoint.vout
364289
),
365-
Self::TransactionNotFound { txid } => {
290+
Self::TransactionNotFound(txid) => {
366291
write!(
367292
f,
368293
"Transaction not found in the internal database with txid: {}",
369294
txid
370295
)
371296
}
372-
Self::TransactionConfirmed { txid } => {
297+
Self::TransactionConfirmed(txid) => {
373298
write!(f, "Transaction already confirmed with txid: {}", txid)
374299
}
375-
Self::IrreplaceableTransaction { txid } => {
300+
Self::IrreplaceableTransaction(txid) => {
376301
write!(f, "Transaction can't be replaced with txid: {}", txid)
377302
}
378303
Self::FeeRateUnavailable => write!(f, "Fee rate unavailable"),
@@ -406,3 +331,98 @@ impl fmt::Display for SignError {
406331

407332
#[cfg(feature = "std")]
408333
impl std::error::Error for SignError {}
334+
335+
#[derive(Debug)]
336+
/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
337+
///
338+
/// [`TxBuilder::add_utxo`]: wallet::tx_builder::TxBuilder::add_utxo
339+
/// [`TxBuilder::add_utxos`]: wallet::tx_builder::TxBuilder::add_utxos
340+
pub enum AddUtxoError {
341+
/// Happens when trying to spend an UTXO that is not in the internal database
342+
UnknownUtxo(OutPoint),
343+
}
344+
345+
#[cfg(feature = "std")]
346+
impl fmt::Display for AddUtxoError {
347+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348+
match self {
349+
Self::UnknownUtxo(outpoint) => write!(
350+
f,
351+
"UTXO not found in the internal database for txid: {} with vout: {}",
352+
outpoint.txid, outpoint.vout
353+
),
354+
}
355+
}
356+
}
357+
358+
#[cfg(feature = "std")]
359+
impl std::error::Error for AddUtxoError {}
360+
361+
#[derive(Debug)]
362+
/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
363+
///
364+
/// [`TxBuilder::add_utxo`]: wallet::tx_builder::TxBuilder::add_utxo
365+
/// [`TxBuilder::add_utxos`]: wallet::tx_builder::TxBuilder::add_utxos
366+
pub enum AddForeignUtxoError {
367+
/// Foreign utxo outpoint txid does not match PSBT input txid
368+
InvalidTxid {
369+
/// PSBT input txid
370+
input_txid: Txid,
371+
/// Foreign UTXO outpoint
372+
foreign_utxo: OutPoint,
373+
},
374+
/// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
375+
InvalidOutpoint(OutPoint),
376+
/// Foreign utxo missing witness_utxo or non_witness_utxo
377+
MissingUtxo,
378+
}
379+
380+
#[cfg(feature = "std")]
381+
impl fmt::Display for AddForeignUtxoError {
382+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383+
match self {
384+
Self::InvalidTxid {
385+
input_txid,
386+
foreign_utxo,
387+
} => write!(
388+
f,
389+
"Foreign UTXO outpoint txid: {} does not match PSBT input txid: {}",
390+
foreign_utxo.txid, input_txid,
391+
),
392+
Self::InvalidOutpoint(outpoint) => write!(
393+
f,
394+
"Requested outpoint doesn't exist for txid: {} with vout: {}",
395+
outpoint.txid, outpoint.vout,
396+
),
397+
Self::MissingUtxo => write!(f, "Foreign utxo missing witness_utxo or non_witness_utxo"),
398+
}
399+
}
400+
}
401+
402+
#[cfg(feature = "std")]
403+
impl std::error::Error for AddForeignUtxoError {}
404+
405+
#[derive(Debug)]
406+
/// Error returned from [`TxBuilder::allow_shrinking`]
407+
///
408+
/// [`TxBuilder::allow_shrinking`]: wallet::tx_builder::TxBuilder::allow_shrinking
409+
pub enum AllowShrinkingError {
410+
/// Script/PubKey was not in the original transaction
411+
MissingScriptPubKey(ScriptBuf),
412+
}
413+
414+
#[cfg(feature = "std")]
415+
impl fmt::Display for AllowShrinkingError {
416+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417+
match self {
418+
Self::MissingScriptPubKey(script_buf) => write!(
419+
f,
420+
"Script/PubKey was not in the original transaction: {}",
421+
script_buf,
422+
),
423+
}
424+
}
425+
}
426+
427+
#[cfg(feature = "std")]
428+
impl std::error::Error for AllowShrinkingError {}

crates/bdk/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ pub mod wallet;
3737

3838
pub use descriptor::template;
3939
pub use descriptor::HdKeyPaths;
40-
pub use error::Error;
4140
pub use types::*;
4241
pub use wallet::signer;
4342
pub use wallet::signer::SignOptions;

crates/bdk/src/wallet/mod.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use bitcoin::{
3838
};
3939
use core::fmt;
4040
use core::ops::Deref;
41+
use descriptor::error::Error as DescriptorError;
4142
use miniscript::psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier};
4243

4344
use bdk_chain::tx_graph::CalculateFeeError;
@@ -56,6 +57,7 @@ pub mod hardwaresigner;
5657

5758
pub use utils::IsDust;
5859

60+
use crate::descriptor;
5961
#[allow(deprecated)]
6062
use coin_selection::DefaultCoinSelectionAlgorithm;
6163
use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner};
@@ -67,7 +69,7 @@ use crate::descriptor::{
6769
calc_checksum, into_wallet_descriptor_checked, DerivedDescriptor, DescriptorMeta,
6870
ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor, Policy, XKeyUtils,
6971
};
70-
use crate::error::{BuildFeeBumpError, CreateTxError, Error, MiniscriptPsbtError, SignError};
72+
use crate::error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError, SignError};
7173
use crate::psbt::PsbtUtils;
7274
use crate::signer::SignerError;
7375
use crate::types::*;
@@ -1291,22 +1293,22 @@ impl<D> Wallet<D> {
12911293

12921294
let mut tx = graph
12931295
.get_tx(txid)
1294-
.ok_or(BuildFeeBumpError::TransactionNotFound { txid })?
1296+
.ok_or(BuildFeeBumpError::TransactionNotFound(txid))?
12951297
.clone();
12961298

12971299
let pos = graph
12981300
.get_chain_position(&self.chain, chain_tip, txid)
1299-
.ok_or(BuildFeeBumpError::TransactionNotFound { txid })?;
1301+
.ok_or(BuildFeeBumpError::TransactionNotFound(txid))?;
13001302
if let ChainPosition::Confirmed(_) = pos {
1301-
return Err(BuildFeeBumpError::TransactionConfirmed { txid });
1303+
return Err(BuildFeeBumpError::TransactionConfirmed(txid));
13021304
}
13031305

13041306
if !tx
13051307
.input
13061308
.iter()
13071309
.any(|txin| txin.sequence.to_consensus_u32() <= 0xFFFFFFFD)
13081310
{
1309-
return Err(BuildFeeBumpError::IrreplaceableTransaction { txid: tx.txid() });
1311+
return Err(BuildFeeBumpError::IrreplaceableTransaction(tx.txid()));
13101312
}
13111313

13121314
let fee = self
@@ -1321,18 +1323,14 @@ impl<D> Wallet<D> {
13211323
let original_utxos = original_txin
13221324
.iter()
13231325
.map(|txin| -> Result<_, BuildFeeBumpError> {
1324-
let prev_tx = graph.get_tx(txin.previous_output.txid).ok_or(
1325-
BuildFeeBumpError::UnknownUtxo {
1326-
outpoint: txin.previous_output,
1327-
},
1328-
)?;
1326+
let prev_tx = graph
1327+
.get_tx(txin.previous_output.txid)
1328+
.ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?;
13291329
let txout = &prev_tx.output[txin.previous_output.vout as usize];
13301330

13311331
let confirmation_time: ConfirmationTime = graph
13321332
.get_chain_position(&self.chain, chain_tip, txin.previous_output.txid)
1333-
.ok_or(BuildFeeBumpError::UnknownUtxo {
1334-
outpoint: txin.previous_output,
1335-
})?
1333+
.ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?
13361334
.cloned()
13371335
.into();
13381336

@@ -1499,7 +1497,7 @@ impl<D> Wallet<D> {
14991497
}
15001498

15011499
/// Return the spending policies for the wallet's descriptor
1502-
pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, Error> {
1500+
pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, DescriptorError> {
15031501
let signers = match keychain {
15041502
KeychainKind::External => &self.signers,
15051503
KeychainKind::Internal => &self.change_signers,
@@ -2054,7 +2052,7 @@ pub fn wallet_name_from_descriptor<T>(
20542052
change_descriptor: Option<T>,
20552053
network: Network,
20562054
secp: &SecpCtx,
2057-
) -> Result<String, Error>
2055+
) -> Result<String, DescriptorError>
20582056
where
20592057
T: IntoWalletDescriptor,
20602058
{

crates/bdk/src/wallet/signer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
//! Arc::new(custom_signer)
7777
//! );
7878
//!
79-
//! # Ok::<_, bdk::Error>(())
79+
//! # Ok::<_, anyhow::Error>(())
8080
//! ```
8181
8282
use crate::collections::BTreeMap;

0 commit comments

Comments
 (0)