Skip to content

Commit 6c03ed1

Browse files
committed
refactor(wallet)!: Use SignerError as error type for Wallet::sign() and Wallet::finalize_psbt()
refactor(wallet)!: Add SignerError::MiniscriptPsbt enum variant
1 parent 1014b87 commit 6c03ed1

File tree

6 files changed

+44
-45
lines changed

6 files changed

+44
-45
lines changed

crates/bdk/src/wallet/error.rs

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use crate::descriptor::policy::PolicyError;
1515
use crate::descriptor::DescriptorError;
1616
use crate::wallet::coin_selection;
17-
use crate::{descriptor, wallet, FeeRate, KeychainKind};
17+
use crate::{descriptor, FeeRate, KeychainKind};
1818
use alloc::string::String;
1919
use bitcoin::{absolute, psbt, OutPoint, ScriptBuf, Sequence, Txid};
2020
use core::fmt;
@@ -291,29 +291,6 @@ impl fmt::Display for BuildFeeBumpError {
291291
#[cfg(feature = "std")]
292292
impl std::error::Error for BuildFeeBumpError {}
293293

294-
#[derive(Debug)]
295-
/// Error returned from [`Wallet::sign`]
296-
///
297-
/// [`Wallet::sign`]: wallet::Wallet::sign
298-
pub enum SignError {
299-
/// Signing error
300-
Signer(wallet::signer::SignerError),
301-
/// Miniscript PSBT error
302-
MiniscriptPsbt(MiniscriptPsbtError),
303-
}
304-
305-
impl fmt::Display for SignError {
306-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307-
match self {
308-
Self::Signer(err) => write!(f, "Signer error: {}", err),
309-
Self::MiniscriptPsbt(err) => write!(f, "Miniscript PSBT error: {}", err),
310-
}
311-
}
312-
}
313-
314-
#[cfg(feature = "std")]
315-
impl std::error::Error for SignError {}
316-
317294
#[derive(Debug)]
318295
/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
319296
///
@@ -340,10 +317,9 @@ impl fmt::Display for AddUtxoError {
340317
impl std::error::Error for AddUtxoError {}
341318

342319
#[derive(Debug)]
343-
/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
320+
/// Error returned from [`TxBuilder::add_foreign_utxo`].
344321
///
345-
/// [`TxBuilder::add_utxo`]: wallet::tx_builder::TxBuilder::add_utxo
346-
/// [`TxBuilder::add_utxos`]: wallet::tx_builder::TxBuilder::add_utxos
322+
/// [`TxBuilder::add_foreign_utxo`]: wallet::tx_builder::TxBuilder::add_foreign_utxo
347323
pub enum AddForeignUtxoError {
348324
/// Foreign utxo outpoint txid does not match PSBT input txid
349325
InvalidTxid {

crates/bdk/src/wallet/mod.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ use crate::psbt::PsbtUtils;
7474
use crate::signer::SignerError;
7575
use crate::types::*;
7676
use crate::wallet::coin_selection::Excess::{Change, NoChange};
77-
use crate::wallet::error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError, SignError};
77+
use crate::wallet::error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError};
7878

7979
const COINBASE_MATURITY: u32 = 100;
8080

@@ -1430,7 +1430,7 @@ impl<D> Wallet<D> {
14301430
/// # use bitcoin::*;
14311431
/// # use bdk::*;
14321432
/// # use bdk::wallet::ChangeSet;
1433-
/// # use bdk::wallet::error::{CreateTxError, SignError};
1433+
/// # use bdk::wallet::error::CreateTxError;
14341434
/// # use bdk_chain::PersistBackend;
14351435
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
14361436
/// # let mut wallet = doctest_wallet!();
@@ -1440,18 +1440,18 @@ impl<D> Wallet<D> {
14401440
/// builder.add_recipient(to_address.script_pubkey(), 50_000);
14411441
/// builder.finish()?
14421442
/// };
1443-
/// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
1443+
/// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
14441444
/// assert!(finalized, "we should have signed all the inputs");
14451445
/// # Ok::<(),anyhow::Error>(())
14461446
pub fn sign(
14471447
&self,
14481448
psbt: &mut psbt::PartiallySignedTransaction,
14491449
sign_options: SignOptions,
1450-
) -> Result<bool, SignError> {
1450+
) -> Result<bool, SignerError> {
14511451
// This adds all the PSBT metadata for the inputs, which will help us later figure out how
14521452
// to derive our keys
14531453
self.update_psbt_with_descriptor(psbt)
1454-
.map_err(SignError::MiniscriptPsbt)?;
1454+
.map_err(SignerError::MiniscriptPsbt)?;
14551455

14561456
// If we aren't allowed to use `witness_utxo`, ensure that every input (except p2tr and finalized ones)
14571457
// has the `non_witness_utxo`
@@ -1463,7 +1463,7 @@ impl<D> Wallet<D> {
14631463
.filter(|i| i.tap_internal_key.is_none() && i.tap_merkle_root.is_none())
14641464
.any(|i| i.non_witness_utxo.is_none())
14651465
{
1466-
return Err(SignError::Signer(SignerError::MissingNonWitnessUtxo));
1466+
return Err(SignerError::MissingNonWitnessUtxo);
14671467
}
14681468

14691469
// If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
@@ -1476,7 +1476,7 @@ impl<D> Wallet<D> {
14761476
|| i.sighash_type == Some(TapSighashType::Default.into())
14771477
})
14781478
{
1479-
return Err(SignError::Signer(SignerError::NonStandardSighash));
1479+
return Err(SignerError::NonStandardSighash);
14801480
}
14811481

14821482
for signer in self
@@ -1485,9 +1485,7 @@ impl<D> Wallet<D> {
14851485
.iter()
14861486
.chain(self.change_signers.signers().iter())
14871487
{
1488-
signer
1489-
.sign_transaction(psbt, &sign_options, &self.secp)
1490-
.map_err(SignError::Signer)?;
1488+
signer.sign_transaction(psbt, &sign_options, &self.secp)?;
14911489
}
14921490

14931491
// attempt to finalize
@@ -1531,7 +1529,7 @@ impl<D> Wallet<D> {
15311529
&self,
15321530
psbt: &mut psbt::PartiallySignedTransaction,
15331531
sign_options: SignOptions,
1534-
) -> Result<bool, SignError> {
1532+
) -> Result<bool, SignerError> {
15351533
let chain_tip = self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default();
15361534

15371535
let tx = &psbt.unsigned_tx;
@@ -1541,7 +1539,7 @@ impl<D> Wallet<D> {
15411539
let psbt_input = &psbt
15421540
.inputs
15431541
.get(n)
1544-
.ok_or(SignError::Signer(SignerError::InputIndexOutOfRange))?;
1542+
.ok_or(SignerError::InputIndexOutOfRange)?;
15451543
if psbt_input.final_script_sig.is_some() || psbt_input.final_script_witness.is_some() {
15461544
continue;
15471545
}

crates/bdk/src/wallet/signer.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ use miniscript::{Legacy, Segwitv0, SigType, Tap, ToPublicKey};
103103
use super::utils::SecpCtx;
104104
use crate::descriptor::{DescriptorMeta, XKeyUtils};
105105
use crate::psbt::PsbtUtils;
106+
use crate::wallet::error::MiniscriptPsbtError;
106107

107108
/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
108109
/// multiple of them
@@ -159,6 +160,8 @@ pub enum SignerError {
159160
InvalidSighash,
160161
/// Error while computing the hash to sign
161162
SighashError(sighash::Error),
163+
/// Miniscript PSBT error
164+
MiniscriptPsbt(MiniscriptPsbtError),
162165
/// Error while signing using hardware wallets
163166
#[cfg(feature = "hardware-signer")]
164167
HWIError(hwi::error::Error),
@@ -192,6 +195,7 @@ impl fmt::Display for SignerError {
192195
Self::NonStandardSighash => write!(f, "The psbt contains a non standard sighash"),
193196
Self::InvalidSighash => write!(f, "Invalid SIGHASH for the signing context in use"),
194197
Self::SighashError(err) => write!(f, "Error while computing the hash to sign: {}", err),
198+
Self::MiniscriptPsbt(err) => write!(f, "Miniscript PSBT error: {}", err),
195199
#[cfg(feature = "hardware-signer")]
196200
Self::HWIError(err) => write!(f, "Error while signing using hardware wallets: {}", err),
197201
}

crates/bdk/src/wallet/tx_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ impl<'a, D, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderContext> TxBuilder<'a, D,
551551

552552
/// Finish building the transaction.
553553
///
554-
/// Returns the [`BIP174`] "PSBT" and summary details about the transaction.
554+
/// Returns a new [`Psbt`] per [BIP174].
555555
///
556556
/// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
557557
pub fn finish(self) -> Result<Psbt, CreateTxError<D::WriteError>>

crates/bdk/tests/wallet.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bdk::descriptor::calc_checksum;
33
use bdk::psbt::PsbtUtils;
44
use bdk::signer::{SignOptions, SignerError};
55
use bdk::wallet::coin_selection::{self, LargestFirstCoinSelection};
6-
use bdk::wallet::error::{AddForeignUtxoError, CreateTxError, SignError};
6+
use bdk::wallet::error::{AddForeignUtxoError, CreateTxError};
77
use bdk::wallet::AddressIndex::*;
88
use bdk::wallet::{AddressIndex, AddressInfo, Balance, Wallet};
99
use bdk::{FeeRate, KeychainKind};
@@ -2428,7 +2428,7 @@ fn test_sign_nonstandard_sighash() {
24282428
);
24292429
assert_matches!(
24302430
result,
2431-
Err(SignError::Signer(SignerError::NonStandardSighash)),
2431+
Err(SignerError::NonStandardSighash),
24322432
"Signing failed with the wrong error type"
24332433
);
24342434

@@ -2845,7 +2845,7 @@ fn test_taproot_sign_missing_witness_utxo() {
28452845
);
28462846
assert_matches!(
28472847
result,
2848-
Err(SignError::Signer(SignerError::MissingWitnessUtxo)),
2848+
Err(SignerError::MissingWitnessUtxo),
28492849
"Signing should have failed with the correct error because the witness_utxo is missing"
28502850
);
28512851

@@ -3186,7 +3186,7 @@ fn test_taproot_sign_non_default_sighash() {
31863186
);
31873187
assert_matches!(
31883188
result,
3189-
Err(SignError::Signer(SignerError::NonStandardSighash)),
3189+
Err(SignerError::NonStandardSighash),
31903190
"Signing failed with the wrong error type"
31913191
);
31923192

@@ -3204,7 +3204,7 @@ fn test_taproot_sign_non_default_sighash() {
32043204
);
32053205
assert_matches!(
32063206
result,
3207-
Err(SignError::Signer(SignerError::MissingWitnessUtxo)),
3207+
Err(SignerError::MissingWitnessUtxo),
32083208
"Signing failed with the wrong error type"
32093209
);
32103210

crates/chain/src/tx_graph.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use crate::{
5757
use alloc::collections::vec_deque::VecDeque;
5858
use alloc::vec::Vec;
5959
use bitcoin::{OutPoint, Script, Transaction, TxOut, Txid};
60+
use core::fmt::{self, Formatter};
6061
use core::{
6162
convert::Infallible,
6263
ops::{Deref, RangeInclusive},
@@ -145,6 +146,26 @@ pub enum CalculateFeeError {
145146
NegativeFee(i64),
146147
}
147148

149+
impl fmt::Display for CalculateFeeError {
150+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
151+
match self {
152+
CalculateFeeError::MissingTxOut(outpoints) => write!(
153+
f,
154+
"missing `TxOut` for one or more of the inputs of the tx: {:?}",
155+
outpoints
156+
),
157+
CalculateFeeError::NegativeFee(fee) => write!(
158+
f,
159+
"transaction is invalid according to the graph and has negative fee: {}",
160+
fee
161+
),
162+
}
163+
}
164+
}
165+
166+
#[cfg(feature = "std")]
167+
impl std::error::Error for CalculateFeeError {}
168+
148169
impl<A> TxGraph<A> {
149170
/// Iterate over all tx outputs known by [`TxGraph`].
150171
///

0 commit comments

Comments
 (0)