@@ -15,258 +15,12 @@ use core::pin::pin;
1515use core:: task;
1616
1717use crate :: chain:: chaininterface:: BroadcasterInterface ;
18- use crate :: chain:: ClaimId ;
19- use crate :: prelude:: * ;
2018use crate :: sign:: SignerProvider ;
21- use crate :: util:: async_poll:: { dummy_waker, MaybeSend , MaybeSync } ;
19+ use crate :: util:: async_poll:: dummy_waker;
2220use crate :: util:: logger:: Logger ;
21+ use crate :: util:: wallet_utils:: { CoinSelectionSourceSync , CoinSelectionSourceSyncWrapper } ;
2322
24- use bitcoin:: { OutPoint , Psbt , ScriptBuf , Transaction , TxOut } ;
25-
26- use super :: BumpTransactionEvent ;
27- use super :: {
28- BumpTransactionEventHandler , CoinSelection , CoinSelectionSource , Input , Utxo , Wallet ,
29- WalletSource ,
30- } ;
31-
32- /// An alternative to [`CoinSelectionSourceSync`] that can be implemented and used along
33- /// [`WalletSync`] to provide a default implementation to [`CoinSelectionSourceSync`].
34- ///
35- /// For an asynchronous version of this trait, see [`WalletSource`].
36- // Note that updates to documentation on this trait should be copied to the asynchronous version.
37- pub trait WalletSourceSync {
38- /// Returns all UTXOs, with at least 1 confirmation each, that are available to spend.
39- fn list_confirmed_utxos ( & self ) -> Result < Vec < Utxo > , ( ) > ;
40-
41- /// Returns the previous transaction containing the UTXO referenced by the outpoint.
42- fn get_prevtx ( & self , outpoint : OutPoint ) -> Result < Transaction , ( ) > ;
43-
44- /// Returns a script to use for change above dust resulting from a successful coin selection
45- /// attempt.
46- fn get_change_script ( & self ) -> Result < ScriptBuf , ( ) > ;
47-
48- /// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within
49- /// the transaction known to the wallet (i.e., any provided via
50- /// [`WalletSource::list_confirmed_utxos`]).
51- ///
52- /// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the
53- /// unsigned transaction and then sign it with your wallet.
54- ///
55- /// [`TxIn::script_sig`]: bitcoin::TxIn::script_sig
56- /// [`TxIn::witness`]: bitcoin::TxIn::witness
57- fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > ;
58- }
59-
60- pub ( crate ) struct WalletSourceSyncWrapper < T : Deref > ( T )
61- where
62- T :: Target : WalletSourceSync ;
63-
64- // Implement `Deref` directly on WalletSourceSyncWrapper so that it can be used directly
65- // below, rather than via a wrapper.
66- impl < T : Deref > Deref for WalletSourceSyncWrapper < T >
67- where
68- T :: Target : WalletSourceSync ,
69- {
70- type Target = Self ;
71- fn deref ( & self ) -> & Self {
72- self
73- }
74- }
75-
76- impl < T : Deref > WalletSource for WalletSourceSyncWrapper < T >
77- where
78- T :: Target : WalletSourceSync ,
79- {
80- fn list_confirmed_utxos < ' a > (
81- & ' a self ,
82- ) -> impl Future < Output = Result < Vec < Utxo > , ( ) > > + MaybeSend + ' a {
83- let utxos = self . 0 . list_confirmed_utxos ( ) ;
84- async move { utxos }
85- }
86-
87- fn get_prevtx < ' a > (
88- & ' a self , outpoint : OutPoint ,
89- ) -> impl Future < Output = Result < Transaction , ( ) > > + MaybeSend + ' a {
90- let prevtx = self . 0 . get_prevtx ( outpoint) ;
91- Box :: pin ( async move { prevtx } )
92- }
93-
94- fn get_change_script < ' a > (
95- & ' a self ,
96- ) -> impl Future < Output = Result < ScriptBuf , ( ) > > + MaybeSend + ' a {
97- let script = self . 0 . get_change_script ( ) ;
98- async move { script }
99- }
100-
101- fn sign_psbt < ' a > (
102- & ' a self , psbt : Psbt ,
103- ) -> impl Future < Output = Result < Transaction , ( ) > > + MaybeSend + ' a {
104- let signed_psbt = self . 0 . sign_psbt ( psbt) ;
105- async move { signed_psbt }
106- }
107- }
108-
109- /// A wrapper over [`WalletSourceSync`] that implements [`CoinSelectionSourceSync`] by preferring
110- /// UTXOs that would avoid conflicting double spends. If not enough UTXOs are available to do so,
111- /// conflicting double spends may happen.
112- ///
113- /// For an asynchronous version of this wrapper, see [`Wallet`].
114- // Note that updates to documentation on this struct should be copied to the asynchronous version.
115- pub struct WalletSync < W : Deref + MaybeSync + MaybeSend , L : Logger + MaybeSync + MaybeSend >
116- where
117- W :: Target : WalletSourceSync + MaybeSend ,
118- {
119- wallet : Wallet < WalletSourceSyncWrapper < W > , L > ,
120- }
121-
122- impl < W : Deref + MaybeSync + MaybeSend , L : Logger + MaybeSync + MaybeSend > WalletSync < W , L >
123- where
124- W :: Target : WalletSourceSync + MaybeSend ,
125- {
126- /// Constructs a new [`WalletSync`] instance.
127- pub fn new ( source : W , logger : L ) -> Self {
128- Self { wallet : Wallet :: new ( WalletSourceSyncWrapper ( source) , logger) }
129- }
130- }
131-
132- impl < W : Deref + MaybeSync + MaybeSend , L : Logger + MaybeSync + MaybeSend > CoinSelectionSourceSync
133- for WalletSync < W , L >
134- where
135- W :: Target : WalletSourceSync + MaybeSend + MaybeSync ,
136- {
137- fn select_confirmed_utxos (
138- & self , claim_id : Option < ClaimId > , must_spend : Vec < Input > , must_pay_to : & [ TxOut ] ,
139- target_feerate_sat_per_1000_weight : u32 , max_tx_weight : u64 ,
140- ) -> Result < CoinSelection , ( ) > {
141- let fut = self . wallet . select_confirmed_utxos (
142- claim_id,
143- must_spend,
144- must_pay_to,
145- target_feerate_sat_per_1000_weight,
146- max_tx_weight,
147- ) ;
148- let mut waker = dummy_waker ( ) ;
149- let mut ctx = task:: Context :: from_waker ( & mut waker) ;
150- match pin ! ( fut) . poll ( & mut ctx) {
151- task:: Poll :: Ready ( result) => result,
152- task:: Poll :: Pending => {
153- unreachable ! (
154- "Wallet::select_confirmed_utxos should not be pending in a sync context"
155- ) ;
156- } ,
157- }
158- }
159-
160- fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > {
161- let fut = self . wallet . sign_psbt ( psbt) ;
162- let mut waker = dummy_waker ( ) ;
163- let mut ctx = task:: Context :: from_waker ( & mut waker) ;
164- match pin ! ( fut) . poll ( & mut ctx) {
165- task:: Poll :: Ready ( result) => result,
166- task:: Poll :: Pending => {
167- unreachable ! ( "Wallet::sign_psbt should not be pending in a sync context" ) ;
168- } ,
169- }
170- }
171- }
172-
173- /// An abstraction over a bitcoin wallet that can perform coin selection over a set of UTXOs and can
174- /// sign for them. The coin selection method aims to mimic Bitcoin Core's `fundrawtransaction` RPC,
175- /// which most wallets should be able to satisfy. Otherwise, consider implementing
176- /// [`WalletSourceSync`], which can provide a default implementation of this trait when used with
177- /// [`WalletSync`].
178- ///
179- /// For an asynchronous version of this trait, see [`CoinSelectionSource`].
180- // Note that updates to documentation on this trait should be copied to the asynchronous version.
181- pub trait CoinSelectionSourceSync {
182- /// Performs coin selection of a set of UTXOs, with at least 1 confirmation each, that are
183- /// available to spend. Implementations are free to pick their coin selection algorithm of
184- /// choice, as long as the following requirements are met:
185- ///
186- /// 1. `must_spend` contains a set of [`Input`]s that must be included in the transaction
187- /// throughout coin selection, but must not be returned as part of the result.
188- /// 2. `must_pay_to` contains a set of [`TxOut`]s that must be included in the transaction
189- /// throughout coin selection. In some cases, like when funding an anchor transaction, this
190- /// set is empty. Implementations should ensure they handle this correctly on their end,
191- /// e.g., Bitcoin Core's `fundrawtransaction` RPC requires at least one output to be
192- /// provided, in which case a zero-value empty OP_RETURN output can be used instead.
193- /// 3. Enough inputs must be selected/contributed for the resulting transaction (including the
194- /// inputs and outputs noted above) to meet `target_feerate_sat_per_1000_weight`.
195- /// 4. The final transaction must have a weight smaller than `max_tx_weight`; if this
196- /// constraint can't be met, return an `Err`. In the case of counterparty-signed HTLC
197- /// transactions, we will remove a chunk of HTLCs and try your algorithm again. As for
198- /// anchor transactions, we will try your coin selection again with the same input-output
199- /// set when you call [`ChannelMonitor::rebroadcast_pending_claims`], as anchor transactions
200- /// cannot be downsized.
201- ///
202- /// Implementations must take note that [`Input::satisfaction_weight`] only tracks the weight of
203- /// the input's `script_sig` and `witness`. Some wallets, like Bitcoin Core's, may require
204- /// providing the full input weight. Failing to do so may lead to underestimating fee bumps and
205- /// delaying block inclusion.
206- ///
207- /// The `claim_id` must map to the set of external UTXOs assigned to the claim, such that they
208- /// can be re-used within new fee-bumped iterations of the original claiming transaction,
209- /// ensuring that claims don't double spend each other. If a specific `claim_id` has never had a
210- /// transaction associated with it, and all of the available UTXOs have already been assigned to
211- /// other claims, implementations must be willing to double spend their UTXOs. The choice of
212- /// which UTXOs to double spend is left to the implementation, but it must strive to keep the
213- /// set of other claims being double spent to a minimum.
214- ///
215- /// [`ChannelMonitor::rebroadcast_pending_claims`]: crate::chain::channelmonitor::ChannelMonitor::rebroadcast_pending_claims
216- fn select_confirmed_utxos (
217- & self , claim_id : Option < ClaimId > , must_spend : Vec < Input > , must_pay_to : & [ TxOut ] ,
218- target_feerate_sat_per_1000_weight : u32 , max_tx_weight : u64 ,
219- ) -> Result < CoinSelection , ( ) > ;
220-
221- /// Signs and provides the full witness for all inputs within the transaction known to the
222- /// trait (i.e., any provided via [`CoinSelectionSourceSync::select_confirmed_utxos`]).
223- ///
224- /// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the
225- /// unsigned transaction and then sign it with your wallet.
226- fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > ;
227- }
228-
229- struct CoinSelectionSourceSyncWrapper < T : Deref > ( T )
230- where
231- T :: Target : CoinSelectionSourceSync ;
232-
233- // Implement `Deref` directly on CoinSelectionSourceSyncWrapper so that it can be used directly
234- // below, rather than via a wrapper.
235- impl < T : Deref > Deref for CoinSelectionSourceSyncWrapper < T >
236- where
237- T :: Target : CoinSelectionSourceSync ,
238- {
239- type Target = Self ;
240- fn deref ( & self ) -> & Self {
241- self
242- }
243- }
244-
245- impl < T : Deref > CoinSelectionSource for CoinSelectionSourceSyncWrapper < T >
246- where
247- T :: Target : CoinSelectionSourceSync ,
248- {
249- fn select_confirmed_utxos < ' a > (
250- & ' a self , claim_id : Option < ClaimId > , must_spend : Vec < Input > , must_pay_to : & ' a [ TxOut ] ,
251- target_feerate_sat_per_1000_weight : u32 , max_tx_weight : u64 ,
252- ) -> impl Future < Output = Result < CoinSelection , ( ) > > + MaybeSend + ' a {
253- let coins = self . 0 . select_confirmed_utxos (
254- claim_id,
255- must_spend,
256- must_pay_to,
257- target_feerate_sat_per_1000_weight,
258- max_tx_weight,
259- ) ;
260- async move { coins }
261- }
262-
263- fn sign_psbt < ' a > (
264- & ' a self , psbt : Psbt ,
265- ) -> impl Future < Output = Result < Transaction , ( ) > > + MaybeSend + ' a {
266- let psbt = self . 0 . sign_psbt ( psbt) ;
267- async move { psbt }
268- }
269- }
23+ use super :: { BumpTransactionEvent , BumpTransactionEventHandler } ;
27024
27125/// A handler for [`Event::BumpTransaction`] events that sources confirmed UTXOs from a
27226/// [`CoinSelectionSourceSync`] to fee bump transactions via Child-Pays-For-Parent (CPFP) or
0 commit comments