Skip to content

Commit f3dcb60

Browse files
committed
fix(wallet): remove TxBuilder::allow_shrinking function and TxBuilderContext
1 parent 2f059a1 commit f3dcb60

File tree

3 files changed

+115
-187
lines changed

3 files changed

+115
-187
lines changed

crates/wallet/src/wallet/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub use utils::IsDust;
5959

6060
use coin_selection::DefaultCoinSelectionAlgorithm;
6161
use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner};
62-
use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxParams};
62+
use tx_builder::{FeePolicy, TxBuilder, TxParams};
6363
use utils::{check_nsequence_rbf, After, Older, SecpCtx};
6464

6565
use crate::descriptor::policy::BuildSatisfaction;
@@ -1357,12 +1357,11 @@ impl Wallet {
13571357
/// ```
13581358
///
13591359
/// [`TxBuilder`]: crate::TxBuilder
1360-
pub fn build_tx(&mut self) -> TxBuilder<'_, DefaultCoinSelectionAlgorithm, CreateTx> {
1360+
pub fn build_tx(&mut self) -> TxBuilder<'_, DefaultCoinSelectionAlgorithm> {
13611361
TxBuilder {
13621362
wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
13631363
params: TxParams::default(),
13641364
coin_selection: DefaultCoinSelectionAlgorithm::default(),
1365-
phantom: core::marker::PhantomData,
13661365
}
13671366
}
13681367

@@ -1748,7 +1747,7 @@ impl Wallet {
17481747
pub fn build_fee_bump(
17491748
&mut self,
17501749
txid: Txid,
1751-
) -> Result<TxBuilder<'_, DefaultCoinSelectionAlgorithm, BumpFee>, BuildFeeBumpError> {
1750+
) -> Result<TxBuilder<'_, DefaultCoinSelectionAlgorithm>, BuildFeeBumpError> {
17521751
let graph = self.indexed_graph.graph();
17531752
let txout_index = &self.indexed_graph.index;
17541753
let chain_tip = self.chain.tip().block_id();
@@ -1872,7 +1871,6 @@ impl Wallet {
18721871
wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
18731872
params,
18741873
coin_selection: DefaultCoinSelectionAlgorithm::default(),
1875-
phantom: core::marker::PhantomData,
18761874
})
18771875
}
18781876

crates/wallet/src/wallet/tx_builder.rs

Lines changed: 79 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
//! # use bdk_wallet::*;
2020
//! # use bdk_wallet::wallet::ChangeSet;
2121
//! # use bdk_wallet::wallet::error::CreateTxError;
22-
//! # use bdk_wallet::wallet::tx_builder::CreateTx;
2322
//! # use bdk_persist::PersistBackend;
2423
//! # use anyhow::Error;
2524
//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
@@ -43,31 +42,16 @@
4342
use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
4443
use core::cell::RefCell;
4544
use core::fmt;
46-
use core::marker::PhantomData;
4745

4846
use bitcoin::psbt::{self, Psbt};
4947
use bitcoin::script::PushBytes;
5048
use bitcoin::{absolute, Amount, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid};
5149

52-
use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
50+
use super::coin_selection::CoinSelectionAlgorithm;
5351
use super::{CreateTxError, Wallet};
5452
use crate::collections::{BTreeMap, HashSet};
5553
use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo};
5654

57-
/// Context in which the [`TxBuilder`] is valid
58-
pub trait TxBuilderContext: core::fmt::Debug + Default + Clone {}
59-
60-
/// Marker type to indicate the [`TxBuilder`] is being used to create a new transaction (as opposed
61-
/// to bumping the fee of an existing one).
62-
#[derive(Debug, Default, Clone)]
63-
pub struct CreateTx;
64-
impl TxBuilderContext for CreateTx {}
65-
66-
/// Marker type to indicate the [`TxBuilder`] is being used to bump the fee of an existing transaction.
67-
#[derive(Debug, Default, Clone)]
68-
pub struct BumpFee;
69-
impl TxBuilderContext for BumpFee {}
70-
7155
/// A transaction builder
7256
///
7357
/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After
@@ -123,11 +107,10 @@ impl TxBuilderContext for BumpFee {}
123107
/// [`finish`]: Self::finish
124108
/// [`coin_selection`]: Self::coin_selection
125109
#[derive(Debug)]
126-
pub struct TxBuilder<'a, Cs, Ctx> {
110+
pub struct TxBuilder<'a, Cs> {
127111
pub(crate) wallet: Rc<RefCell<&'a mut Wallet>>,
128112
pub(crate) params: TxParams,
129113
pub(crate) coin_selection: Cs,
130-
pub(crate) phantom: PhantomData<Ctx>,
131114
}
132115

133116
/// The parameters for transaction creation sans coin selection algorithm.
@@ -175,19 +158,18 @@ impl Default for FeePolicy {
175158
}
176159
}
177160

178-
impl<'a, Cs: Clone, Ctx> Clone for TxBuilder<'a, Cs, Ctx> {
161+
impl<'a, Cs: Clone> Clone for TxBuilder<'a, Cs> {
179162
fn clone(&self) -> Self {
180163
TxBuilder {
181164
wallet: self.wallet.clone(),
182165
params: self.params.clone(),
183166
coin_selection: self.coin_selection.clone(),
184-
phantom: PhantomData,
185167
}
186168
}
187169
}
188170

189-
// methods supported by both contexts, for any CoinSelectionAlgorithm
190-
impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
171+
// Methods supported for any CoinSelectionAlgorithm.
172+
impl<'a, Cs> TxBuilder<'a, Cs> {
191173
/// Set a custom fee rate.
192174
///
193175
/// This method sets the mining fee paid by the transaction as a rate on its size.
@@ -212,8 +194,8 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
212194
/// Note that this is really a minimum absolute fee -- it's possible to
213195
/// overshoot it slightly since adding a change output to drain the remaining
214196
/// excess might not be viable.
215-
pub fn fee_absolute(&mut self, fee_amount: u64) -> &mut Self {
216-
self.params.fee_policy = Some(FeePolicy::FeeAmount(fee_amount));
197+
pub fn fee_absolute(&mut self, fee_amount: Amount) -> &mut Self {
198+
self.params.fee_policy = Some(FeePolicy::FeeAmount(fee_amount.to_sat()));
217199
self
218200
}
219201

@@ -556,15 +538,11 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
556538
/// Overrides the [`DefaultCoinSelectionAlgorithm`].
557539
///
558540
/// Note that this function consumes the builder and returns it so it is usually best to put this as the first call on the builder.
559-
pub fn coin_selection<P: CoinSelectionAlgorithm>(
560-
self,
561-
coin_selection: P,
562-
) -> TxBuilder<'a, P, Ctx> {
541+
pub fn coin_selection<P: CoinSelectionAlgorithm>(self, coin_selection: P) -> TxBuilder<'a, P> {
563542
TxBuilder {
564543
wallet: self.wallet,
565544
params: self.params,
566545
coin_selection,
567-
phantom: PhantomData,
568546
}
569547
}
570548

@@ -612,106 +590,7 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
612590
self.params.allow_dust = allow_dust;
613591
self
614592
}
615-
}
616-
617-
impl<'a, Cs: CoinSelectionAlgorithm, Ctx> TxBuilder<'a, Cs, Ctx> {
618-
/// Finish building the transaction.
619-
///
620-
/// Returns a new [`Psbt`] per [`BIP174`].
621-
///
622-
/// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
623-
pub fn finish(self) -> Result<Psbt, CreateTxError> {
624-
self.wallet
625-
.borrow_mut()
626-
.create_tx(self.coin_selection, self.params)
627-
}
628-
}
629-
630-
#[derive(Debug)]
631-
/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
632-
pub enum AddUtxoError {
633-
/// Happens when trying to spend an UTXO that is not in the internal database
634-
UnknownUtxo(OutPoint),
635-
}
636-
637-
impl fmt::Display for AddUtxoError {
638-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
639-
match self {
640-
Self::UnknownUtxo(outpoint) => write!(
641-
f,
642-
"UTXO not found in the internal database for txid: {} with vout: {}",
643-
outpoint.txid, outpoint.vout
644-
),
645-
}
646-
}
647-
}
648-
649-
#[cfg(feature = "std")]
650-
impl std::error::Error for AddUtxoError {}
651-
652-
#[derive(Debug)]
653-
/// Error returned from [`TxBuilder::add_foreign_utxo`].
654-
pub enum AddForeignUtxoError {
655-
/// Foreign utxo outpoint txid does not match PSBT input txid
656-
InvalidTxid {
657-
/// PSBT input txid
658-
input_txid: Txid,
659-
/// Foreign UTXO outpoint
660-
foreign_utxo: OutPoint,
661-
},
662-
/// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
663-
InvalidOutpoint(OutPoint),
664-
/// Foreign utxo missing witness_utxo or non_witness_utxo
665-
MissingUtxo,
666-
}
667-
668-
impl fmt::Display for AddForeignUtxoError {
669-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
670-
match self {
671-
Self::InvalidTxid {
672-
input_txid,
673-
foreign_utxo,
674-
} => write!(
675-
f,
676-
"Foreign UTXO outpoint txid: {} does not match PSBT input txid: {}",
677-
foreign_utxo.txid, input_txid,
678-
),
679-
Self::InvalidOutpoint(outpoint) => write!(
680-
f,
681-
"Requested outpoint doesn't exist for txid: {} with vout: {}",
682-
outpoint.txid, outpoint.vout,
683-
),
684-
Self::MissingUtxo => write!(f, "Foreign utxo missing witness_utxo or non_witness_utxo"),
685-
}
686-
}
687-
}
688-
689-
#[cfg(feature = "std")]
690-
impl std::error::Error for AddForeignUtxoError {}
691-
692-
#[derive(Debug)]
693-
/// Error returned from [`TxBuilder::allow_shrinking`]
694-
pub enum AllowShrinkingError {
695-
/// Script/PubKey was not in the original transaction
696-
MissingScriptPubKey(ScriptBuf),
697-
}
698-
699-
impl fmt::Display for AllowShrinkingError {
700-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
701-
match self {
702-
Self::MissingScriptPubKey(script_buf) => write!(
703-
f,
704-
"Script/PubKey was not in the original transaction: {}",
705-
script_buf,
706-
),
707-
}
708-
}
709-
}
710-
711-
#[cfg(feature = "std")]
712-
impl std::error::Error for AllowShrinkingError {}
713593

714-
impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
715594
/// Replace the recipients already added with a new list
716595
pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, Amount)>) -> &mut Self {
717596
self.params.recipients = recipients
@@ -745,11 +624,8 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
745624
/// difference is that it is valid to use `drain_to` without setting any ordinary recipients
746625
/// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
747626
///
748-
/// If you choose not to set any recipients, you should either provide the utxos that the
749-
/// transaction should spend via [`add_utxos`], or set [`drain_wallet`] to spend all of them.
750-
///
751-
/// When bumping the fees of a transaction made with this option, you probably want to
752-
/// use [`allow_shrinking`] to allow this output to be reduced to pay for the extra fees.
627+
/// If you choose not to set any recipients, you should provide the utxos that the
628+
/// transaction should spend via [`add_utxos`].
753629
///
754630
/// # Example
755631
///
@@ -762,7 +638,6 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
762638
/// # use bdk_wallet::*;
763639
/// # use bdk_wallet::wallet::ChangeSet;
764640
/// # use bdk_wallet::wallet::error::CreateTxError;
765-
/// # use bdk_wallet::wallet::tx_builder::CreateTx;
766641
/// # use bdk_persist::PersistBackend;
767642
/// # use anyhow::Error;
768643
/// # let to_address =
@@ -783,7 +658,6 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
783658
/// # Ok::<(), anyhow::Error>(())
784659
/// ```
785660
///
786-
/// [`allow_shrinking`]: Self::allow_shrinking
787661
/// [`add_recipient`]: Self::add_recipient
788662
/// [`add_utxos`]: Self::add_utxos
789663
/// [`drain_wallet`]: Self::drain_wallet
@@ -793,38 +667,81 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
793667
}
794668
}
795669

796-
// methods supported only by bump_fee
797-
impl<'a> TxBuilder<'a, DefaultCoinSelectionAlgorithm, BumpFee> {
798-
/// Explicitly tells the wallet that it is allowed to reduce the amount of the output matching this
799-
/// `script_pubkey` in order to bump the transaction fee. Without specifying this the wallet
800-
/// will attempt to find a change output to shrink instead.
670+
impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs> {
671+
/// Finish building the transaction.
801672
///
802-
/// **Note** that the output may shrink to below the dust limit and therefore be removed. If it is
803-
/// preserved then it is currently not guaranteed to be in the same position as it was
804-
/// originally.
673+
/// Returns a new [`Psbt`] per [`BIP174`].
805674
///
806-
/// Returns an `Err` if `script_pubkey` can't be found among the recipients of the
807-
/// transaction we are bumping.
808-
pub fn allow_shrinking(
809-
&mut self,
810-
script_pubkey: ScriptBuf,
811-
) -> Result<&mut Self, AllowShrinkingError> {
812-
match self
813-
.params
814-
.recipients
815-
.iter()
816-
.position(|(recipient_script, _)| *recipient_script == script_pubkey)
817-
{
818-
Some(position) => {
819-
self.params.recipients.remove(position);
820-
self.params.drain_to = Some(script_pubkey);
821-
Ok(self)
822-
}
823-
None => Err(AllowShrinkingError::MissingScriptPubKey(script_pubkey)),
675+
/// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
676+
pub fn finish(self) -> Result<Psbt, CreateTxError> {
677+
self.wallet
678+
.borrow_mut()
679+
.create_tx(self.coin_selection, self.params)
680+
}
681+
}
682+
683+
#[derive(Debug)]
684+
/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
685+
pub enum AddUtxoError {
686+
/// Happens when trying to spend an UTXO that is not in the internal database
687+
UnknownUtxo(OutPoint),
688+
}
689+
690+
impl fmt::Display for AddUtxoError {
691+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692+
match self {
693+
Self::UnknownUtxo(outpoint) => write!(
694+
f,
695+
"UTXO not found in the internal database for txid: {} with vout: {}",
696+
outpoint.txid, outpoint.vout
697+
),
698+
}
699+
}
700+
}
701+
702+
#[cfg(feature = "std")]
703+
impl std::error::Error for AddUtxoError {}
704+
705+
#[derive(Debug)]
706+
/// Error returned from [`TxBuilder::add_foreign_utxo`].
707+
pub enum AddForeignUtxoError {
708+
/// Foreign utxo outpoint txid does not match PSBT input txid
709+
InvalidTxid {
710+
/// PSBT input txid
711+
input_txid: Txid,
712+
/// Foreign UTXO outpoint
713+
foreign_utxo: OutPoint,
714+
},
715+
/// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
716+
InvalidOutpoint(OutPoint),
717+
/// Foreign utxo missing witness_utxo or non_witness_utxo
718+
MissingUtxo,
719+
}
720+
721+
impl fmt::Display for AddForeignUtxoError {
722+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
723+
match self {
724+
Self::InvalidTxid {
725+
input_txid,
726+
foreign_utxo,
727+
} => write!(
728+
f,
729+
"Foreign UTXO outpoint txid: {} does not match PSBT input txid: {}",
730+
foreign_utxo.txid, input_txid,
731+
),
732+
Self::InvalidOutpoint(outpoint) => write!(
733+
f,
734+
"Requested outpoint doesn't exist for txid: {} with vout: {}",
735+
outpoint.txid, outpoint.vout,
736+
),
737+
Self::MissingUtxo => write!(f, "Foreign utxo missing witness_utxo or non_witness_utxo"),
824738
}
825739
}
826740
}
827741

742+
#[cfg(feature = "std")]
743+
impl std::error::Error for AddForeignUtxoError {}
744+
828745
/// Ordering of the transaction's inputs and outputs
829746
#[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
830747
pub enum TxOrdering {

0 commit comments

Comments
 (0)