Skip to content

Commit 43cc817

Browse files
committed
refactor(wallet)!: move CreateTxError to error module, make error module public
1 parent 8c8f050 commit 43cc817

File tree

6 files changed

+234
-221
lines changed

6 files changed

+234
-221
lines changed

crates/bdk/src/error.rs

Lines changed: 213 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99
// You may not use this file except in accordance with one or both of these
1010
// licenses.
1111

12-
use crate::bitcoin::Network;
13-
use crate::{descriptor, wallet};
14-
use alloc::{string::String, vec::Vec};
15-
use bitcoin::{OutPoint, Txid};
12+
//! Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet)
13+
14+
use crate::descriptor::policy::PolicyError;
15+
use crate::descriptor::DescriptorError;
16+
use crate::wallet::coin_selection;
17+
use crate::{descriptor, wallet, FeeRate, KeychainKind};
18+
use alloc::string::String;
19+
use bitcoin::{absolute, psbt, OutPoint, Sequence};
1620
use core::fmt;
1721

18-
/// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet)
22+
/// Old catch-all errors enum that can be thrown by the [`Wallet`](crate::wallet::Wallet)
1923
#[derive(Debug)]
2024
pub enum Error {
2125
/// Generic error
@@ -53,8 +57,11 @@ pub enum Error {
5357
/// Errors returned by miniscript when updating inconsistent PSBTs
5458
#[derive(Debug, Clone)]
5559
pub enum MiniscriptPsbtError {
60+
/// Descriptor key conversion error
5661
Conversion(miniscript::descriptor::ConversionError),
62+
/// Return error type for PsbtExt::update_input_with_descriptor
5763
UtxoUpdate(miniscript::psbt::UtxoUpdateError),
64+
/// Return error type for PsbtExt::update_output_with_descriptor
5865
OutputUpdate(miniscript::psbt::OutputUpdateError),
5966
}
6067

@@ -134,3 +141,204 @@ impl_error!(miniscript::Error, Miniscript);
134141
impl_error!(MiniscriptPsbtError, MiniscriptPsbt);
135142
impl_error!(bitcoin::bip32::Error, Bip32);
136143
impl_error!(bitcoin::psbt::Error, Psbt);
144+
145+
#[derive(Debug)]
146+
/// Error returned from [`TxBuilder::finish`]
147+
pub enum CreateTxError<P> {
148+
/// There was a problem with the descriptors passed in
149+
Descriptor(DescriptorError),
150+
/// We were unable to write wallet data to the persistence backend
151+
Persist(P),
152+
/// There was a problem while extracting and manipulating policies
153+
Policy(PolicyError),
154+
/// Spending policy is not compatible with this [`KeychainKind`](crate::types::KeychainKind)
155+
SpendingPolicyRequired(KeychainKind),
156+
/// Requested invalid transaction version '0'
157+
Version0,
158+
/// Requested transaction version `1`, but at least `2` is needed to use OP_CSV
159+
Version1Csv,
160+
/// Requested `LockTime` is less than is required to spend from this script
161+
LockTime {
162+
/// Requested `LockTime`
163+
requested: absolute::LockTime,
164+
/// Required `LockTime`
165+
required: absolute::LockTime,
166+
},
167+
/// Cannot enable RBF with a `Sequence` >= 0xFFFFFFFE
168+
RbfSequence,
169+
/// Cannot enable RBF with `Sequence` given a required OP_CSV
170+
RbfSequenceCsv {
171+
/// Given RBF `Sequence`
172+
rbf: Sequence,
173+
/// Required OP_CSV `Sequence`
174+
csv: Sequence,
175+
},
176+
/// When bumping a tx the absolute fee requested is lower than replaced tx absolute fee
177+
FeeTooLow {
178+
/// Required fee absolute value (satoshi)
179+
required: u64,
180+
},
181+
/// When bumping a tx the fee rate requested is lower than required
182+
FeeRateTooLow {
183+
/// Required fee rate (satoshi/vbyte)
184+
required: FeeRate,
185+
},
186+
/// `manually_selected_only` option is selected but no utxo has been passed
187+
NoUtxosSelected,
188+
/// Output created is under the dust limit, 546 satoshis
189+
OutputBelowDustLimit(usize),
190+
/// The `change_policy` was set but the wallet does not have a change_descriptor
191+
ChangePolicyDescriptor,
192+
/// There was an error with coin selection
193+
CoinSelection(coin_selection::Error),
194+
/// Wallet's UTXO set is not enough to cover recipient's requested plus fee
195+
InsufficientFunds {
196+
/// Sats needed for some transaction
197+
needed: u64,
198+
/// Sats available for spending
199+
available: u64,
200+
},
201+
/// Cannot build a tx without recipients
202+
NoRecipients,
203+
/// Partially signed bitcoin transaction error
204+
Psbt(psbt::Error),
205+
/// In order to use the [`TxBuilder::add_global_xpubs`] option every extended
206+
/// key in the descriptor must either be a master key itself (having depth = 0) or have an
207+
/// explicit origin provided
208+
///
209+
/// [`TxBuilder::add_global_xpubs`]: crate::wallet::tx_builder::TxBuilder::add_global_xpubs
210+
MissingKeyOrigin(String),
211+
/// Happens when trying to spend an UTXO that is not in the internal database
212+
UnknownUtxo,
213+
/// Missing non_witness_utxo on foreign utxo for given `OutPoint`
214+
MissingNonWitnessUtxo(OutPoint),
215+
/// Miniscript PSBT error
216+
MiniscriptPsbt(MiniscriptPsbtError),
217+
}
218+
219+
#[cfg(feature = "std")]
220+
impl<P> fmt::Display for CreateTxError<P>
221+
where
222+
P: fmt::Display,
223+
{
224+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225+
match self {
226+
Self::Descriptor(e) => e.fmt(f),
227+
Self::Persist(e) => {
228+
write!(
229+
f,
230+
"failed to write wallet data to persistence backend: {}",
231+
e
232+
)
233+
}
234+
Self::Policy(e) => e.fmt(f),
235+
CreateTxError::SpendingPolicyRequired(keychain_kind) => {
236+
write!(f, "Spending policy required: {:?}", keychain_kind)
237+
}
238+
CreateTxError::Version0 => {
239+
write!(f, "Invalid version `0`")
240+
}
241+
CreateTxError::Version1Csv => {
242+
write!(
243+
f,
244+
"TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
245+
)
246+
}
247+
CreateTxError::LockTime {
248+
requested,
249+
required,
250+
} => {
251+
write!(f, "TxBuilder requested timelock of `{:?}`, but at least `{:?}` is required to spend from this script", required, requested)
252+
}
253+
CreateTxError::RbfSequence => {
254+
write!(f, "Cannot enable RBF with a nSequence >= 0xFFFFFFFE")
255+
}
256+
CreateTxError::RbfSequenceCsv { rbf, csv } => {
257+
write!(
258+
f,
259+
"Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}`",
260+
rbf, csv
261+
)
262+
}
263+
CreateTxError::FeeTooLow { required } => {
264+
write!(f, "Fee to low: required {} sat", required)
265+
}
266+
CreateTxError::FeeRateTooLow { required } => {
267+
write!(
268+
f,
269+
"Fee rate too low: required {} sat/vbyte",
270+
required.as_sat_per_vb()
271+
)
272+
}
273+
CreateTxError::NoUtxosSelected => {
274+
write!(f, "No UTXO selected")
275+
}
276+
CreateTxError::OutputBelowDustLimit(limit) => {
277+
write!(f, "Output below the dust limit: {}", limit)
278+
}
279+
CreateTxError::ChangePolicyDescriptor => {
280+
write!(
281+
f,
282+
"The `change_policy` can be set only if the wallet has a change_descriptor"
283+
)
284+
}
285+
CreateTxError::CoinSelection(e) => e.fmt(f),
286+
CreateTxError::InsufficientFunds { needed, available } => {
287+
write!(
288+
f,
289+
"Insufficient funds: {} sat available of {} sat needed",
290+
available, needed
291+
)
292+
}
293+
CreateTxError::NoRecipients => {
294+
write!(f, "Cannot build tx without recipients")
295+
}
296+
CreateTxError::Psbt(e) => e.fmt(f),
297+
CreateTxError::MissingKeyOrigin(err) => {
298+
write!(f, "Missing key origin: {}", err)
299+
}
300+
CreateTxError::UnknownUtxo => {
301+
write!(f, "UTXO not found in the internal database")
302+
}
303+
CreateTxError::MissingNonWitnessUtxo(outpoint) => {
304+
write!(f, "Missing non_witness_utxo on foreign utxo {}", outpoint)
305+
}
306+
CreateTxError::MiniscriptPsbt(err) => {
307+
write!(f, "Miniscript PSBT error: {}", err)
308+
}
309+
}
310+
}
311+
}
312+
313+
impl<P> From<descriptor::error::Error> for CreateTxError<P> {
314+
fn from(err: descriptor::error::Error) -> Self {
315+
CreateTxError::Descriptor(err)
316+
}
317+
}
318+
319+
impl<P> From<PolicyError> for CreateTxError<P> {
320+
fn from(err: PolicyError) -> Self {
321+
CreateTxError::Policy(err)
322+
}
323+
}
324+
325+
impl<P> From<MiniscriptPsbtError> for CreateTxError<P> {
326+
fn from(err: MiniscriptPsbtError) -> Self {
327+
CreateTxError::MiniscriptPsbt(err)
328+
}
329+
}
330+
331+
impl<P> From<psbt::Error> for CreateTxError<P> {
332+
fn from(err: psbt::Error) -> Self {
333+
CreateTxError::Psbt(err)
334+
}
335+
}
336+
337+
impl<P> From<coin_selection::Error> for CreateTxError<P> {
338+
fn from(err: coin_selection::Error) -> Self {
339+
CreateTxError::CoinSelection(err)
340+
}
341+
}
342+
343+
#[cfg(feature = "std")]
344+
impl<P: core::fmt::Display + core::fmt::Debug> std::error::Error for CreateTxError<P> {}

crates/bdk/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ extern crate serde_json;
2727
#[cfg(feature = "keys-bip39")]
2828
extern crate bip39;
2929

30-
#[allow(unused_imports)]
3130
#[macro_use]
32-
pub(crate) mod error;
31+
pub mod error;
3332
pub mod descriptor;
3433
pub mod keys;
3534
pub mod psbt;

crates/bdk/src/wallet/coin_selection.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
//! ```
2727
//! # use std::str::FromStr;
2828
//! # use bitcoin::*;
29-
//! # use bdk::wallet::{self, ChangeSet, coin_selection::*, coin_selection, CreateTxError};
29+
//! # use bdk::wallet::{self, ChangeSet, coin_selection::*, coin_selection};
30+
//! # use bdk::error::CreateTxError;
3031
//! # use bdk_chain::PersistBackend;
3132
//! # use bdk::*;
3233
//! # use bdk::wallet::coin_selection::decide_change;

0 commit comments

Comments
 (0)