@@ -30,6 +30,7 @@ use crate::ln::chan_utils::{
3030 HTLC_TIMEOUT_INPUT_KEYED_ANCHOR_WITNESS_WEIGHT , HTLC_TIMEOUT_INPUT_P2A_ANCHOR_WITNESS_WEIGHT ,
3131 P2WSH_TXOUT_WEIGHT , SEGWIT_MARKER_FLAG_WEIGHT , TRUC_CHILD_MAX_WEIGHT , TRUC_MAX_WEIGHT ,
3232} ;
33+ use crate :: ln:: funding:: FundingTxInput ;
3334use crate :: ln:: types:: ChannelId ;
3435use crate :: prelude:: * ;
3536use crate :: sign:: ecdsa:: EcdsaChannelSigner ;
@@ -340,20 +341,33 @@ impl Utxo {
340341 }
341342}
342343
344+ /// An unspent transaction output with at least one confirmation.
345+ pub type ConfirmedUtxo = FundingTxInput ;
346+
343347/// The result of a successful coin selection attempt for a transaction requiring additional UTXOs
344348/// to cover its fees.
345349#[ derive( Clone , Debug ) ]
346350pub struct CoinSelection {
347351 /// The set of UTXOs (with at least 1 confirmation) to spend and use within a transaction
348352 /// requiring additional fees.
349- pub confirmed_utxos : Vec < Utxo > ,
353+ pub confirmed_utxos : Vec < ConfirmedUtxo > ,
350354 /// An additional output tracking whether any change remained after coin selection. This output
351355 /// should always have a value above dust for its given `script_pubkey`. It should not be
352356 /// spent until the transaction it belongs to confirms to ensure mempool descendant limits are
353357 /// not met. This implies no other party should be able to spend it except us.
354358 pub change_output : Option < TxOut > ,
355359}
356360
361+ impl CoinSelection {
362+ fn satisfaction_weight ( & self ) -> u64 {
363+ self . confirmed_utxos . iter ( ) . map ( |ConfirmedUtxo { utxo, .. } | utxo. satisfaction_weight ) . sum ( )
364+ }
365+
366+ fn amount ( & self ) -> Amount {
367+ self . confirmed_utxos . iter ( ) . map ( |ConfirmedUtxo { utxo, .. } | utxo. output . value ) . sum ( )
368+ }
369+ }
370+
357371/// An abstraction over a bitcoin wallet that can perform coin selection over a set of UTXOs and can
358372/// sign for them. The coin selection method aims to mimic Bitcoin Core's `fundrawtransaction` RPC,
359373/// which most wallets should be able to satisfy. Otherwise, consider implementing [`WalletSource`],
@@ -424,11 +438,18 @@ pub trait WalletSource {
424438 fn list_confirmed_utxos < ' a > (
425439 & ' a self ,
426440 ) -> impl Future < Output = Result < Vec < Utxo > , ( ) > > + MaybeSend + ' a ;
441+
442+ /// Returns the previous transaction containing the UTXO.
443+ fn get_prevtx < ' a > (
444+ & ' a self , utxo : & Utxo ,
445+ ) -> impl Future < Output = Result < Transaction , ( ) > > + MaybeSend + ' a ;
446+
427447 /// Returns a script to use for change above dust resulting from a successful coin selection
428448 /// attempt.
429449 fn get_change_script < ' a > (
430450 & ' a self ,
431451 ) -> impl Future < Output = Result < ScriptBuf , ( ) > > + MaybeSend + ' a ;
452+
432453 /// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within
433454 /// the transaction known to the wallet (i.e., any provided via
434455 /// [`WalletSource::list_confirmed_utxos`]).
@@ -616,10 +637,13 @@ where
616637 Some ( TxOut { script_pubkey : change_script, value : change_output_amount } )
617638 } ;
618639
619- Ok ( CoinSelection {
620- confirmed_utxos : selected_utxos. into_iter ( ) . map ( |( utxo, _) | utxo) . collect ( ) ,
621- change_output,
622- } )
640+ let mut confirmed_utxos = Vec :: with_capacity ( selected_utxos. len ( ) ) ;
641+ for ( utxo, _) in selected_utxos {
642+ let prevtx = self . source . get_prevtx ( & utxo) . await ?;
643+ confirmed_utxos. push ( ConfirmedUtxo { utxo, prevtx } ) ;
644+ }
645+
646+ Ok ( CoinSelection { confirmed_utxos, change_output } )
623647 }
624648}
625649
@@ -730,7 +754,7 @@ where
730754
731755 /// Updates a transaction with the result of a successful coin selection attempt.
732756 fn process_coin_selection ( & self , tx : & mut Transaction , coin_selection : & CoinSelection ) {
733- for utxo in coin_selection. confirmed_utxos . iter ( ) {
757+ for ConfirmedUtxo { utxo, .. } in coin_selection. confirmed_utxos . iter ( ) {
734758 tx. input . push ( TxIn {
735759 previous_output : utxo. outpoint ,
736760 script_sig : ScriptBuf :: new ( ) ,
@@ -852,12 +876,10 @@ where
852876 output : vec ! [ ] ,
853877 } ;
854878
855- let input_satisfaction_weight: u64 =
856- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. satisfaction_weight ) . sum ( ) ;
879+ let input_satisfaction_weight = coin_selection. satisfaction_weight ( ) ;
857880 let total_satisfaction_weight =
858881 anchor_input_witness_weight + EMPTY_SCRIPT_SIG_WEIGHT + input_satisfaction_weight;
859- let total_input_amount = must_spend_amount
860- + coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value ) . sum ( ) ;
882+ let total_input_amount = must_spend_amount + coin_selection. amount ( ) ;
861883
862884 self . process_coin_selection ( & mut anchor_tx, & coin_selection) ;
863885 let anchor_txid = anchor_tx. compute_txid ( ) ;
@@ -872,10 +894,10 @@ where
872894 let index = idx + 1 ;
873895 debug_assert_eq ! (
874896 anchor_psbt. unsigned_tx. input[ index] . previous_output,
875- utxo. outpoint
897+ utxo. outpoint( )
876898 ) ;
877- if utxo. output . script_pubkey . is_witness_program ( ) {
878- anchor_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
899+ if utxo. output ( ) . script_pubkey . is_witness_program ( ) {
900+ anchor_psbt. inputs [ index] . witness_utxo = Some ( utxo. into_output ( ) ) ;
879901 }
880902 }
881903
@@ -1107,13 +1129,11 @@ where
11071129 utxo_id = claim_id. step_with_bytes ( & broadcasted_htlcs. to_be_bytes ( ) ) ;
11081130
11091131 #[ cfg( debug_assertions) ]
1110- let input_satisfaction_weight: u64 =
1111- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. satisfaction_weight ) . sum ( ) ;
1132+ let input_satisfaction_weight = coin_selection. satisfaction_weight ( ) ;
11121133 #[ cfg( debug_assertions) ]
11131134 let total_satisfaction_weight = must_spend_satisfaction_weight + input_satisfaction_weight;
11141135 #[ cfg( debug_assertions) ]
1115- let input_value: u64 =
1116- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value . to_sat ( ) ) . sum ( ) ;
1136+ let input_value = coin_selection. amount ( ) . to_sat ( ) ;
11171137 #[ cfg( debug_assertions) ]
11181138 let total_input_amount = must_spend_amount + input_value;
11191139
@@ -1134,9 +1154,12 @@ where
11341154 for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
11351155 // offset to skip the htlc inputs
11361156 let index = idx + selected_htlcs. len ( ) ;
1137- debug_assert_eq ! ( htlc_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
1138- if utxo. output . script_pubkey . is_witness_program ( ) {
1139- htlc_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
1157+ debug_assert_eq ! (
1158+ htlc_psbt. unsigned_tx. input[ index] . previous_output,
1159+ utxo. outpoint( )
1160+ ) ;
1161+ if utxo. output ( ) . script_pubkey . is_witness_program ( ) {
1162+ htlc_psbt. inputs [ index] . witness_utxo = Some ( utxo. into_output ( ) ) ;
11401163 }
11411164 }
11421165
@@ -1280,9 +1303,8 @@ mod tests {
12801303 use crate :: util:: ser:: Readable ;
12811304 use crate :: util:: test_utils:: { TestBroadcaster , TestLogger } ;
12821305
1283- use bitcoin:: hashes:: Hash ;
12841306 use bitcoin:: hex:: FromHex ;
1285- use bitcoin:: { Network , ScriptBuf , Transaction , Txid } ;
1307+ use bitcoin:: { Network , ScriptBuf , Transaction } ;
12861308
12871309 struct TestCoinSelectionSource {
12881310 // (commitment + anchor value, commitment + input weight, target feerate, result)
@@ -1302,8 +1324,12 @@ mod tests {
13021324 Ok ( res)
13031325 }
13041326 fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > {
1305- // FIXME: Why does handle_channel_close override the witness?
1306- Ok ( psbt. unsigned_tx )
1327+ let mut tx = psbt. unsigned_tx ;
1328+ // Channel output, add a realistic size witness to make the assertions happy
1329+ //
1330+ // FIXME: This doesn't seem to be needed since handle_channel_close overrides it
1331+ tx. input . first_mut ( ) . unwrap ( ) . witness = Witness :: from_slice ( & [ vec ! [ 42 ; 162 ] ] ) ;
1332+ Ok ( tx)
13071333 }
13081334 }
13091335
@@ -1339,6 +1365,13 @@ mod tests {
13391365 . weight ( )
13401366 . to_wu ( ) ;
13411367
1368+ let prevtx = Transaction {
1369+ version : Version :: TWO ,
1370+ lock_time : LockTime :: ZERO ,
1371+ input : vec ! [ ] ,
1372+ output : vec ! [ TxOut { value: Amount :: from_sat( 200 ) , script_pubkey: ScriptBuf :: new( ) } ] ,
1373+ } ;
1374+
13421375 let broadcaster = TestBroadcaster :: new ( Network :: Testnet ) ;
13431376 let source = TestCoinSelectionSource {
13441377 expected_selects : Mutex :: new ( vec ! [
@@ -1353,14 +1386,14 @@ mod tests {
13531386 commitment_and_anchor_fee,
13541387 868 ,
13551388 CoinSelection {
1356- confirmed_utxos: vec![ Utxo {
1357- outpoint: OutPoint { txid: Txid :: from_byte_array( [ 44 ; 32 ] ) , vout: 0 } ,
1358- output: TxOut {
1359- value: Amount :: from_sat( 200 ) ,
1360- script_pubkey: ScriptBuf :: new( ) ,
1389+ confirmed_utxos: vec![ ConfirmedUtxo {
1390+ utxo: Utxo {
1391+ outpoint: OutPoint { txid: prevtx. compute_txid( ) , vout: 0 } ,
1392+ output: prevtx. output[ 0 ] . clone( ) ,
1393+ satisfaction_weight: 5 , // Just the script_sig and witness lengths
1394+ sequence: Sequence :: ENABLE_RBF_NO_LOCKTIME ,
13611395 } ,
1362- satisfaction_weight: 5 , // Just the script_sig and witness lengths
1363- sequence: Sequence :: ENABLE_RBF_NO_LOCKTIME ,
1396+ prevtx,
13641397 } ] ,
13651398 change_output: None ,
13661399 } ,
0 commit comments