@@ -582,11 +582,25 @@ where
582
582
// match, but we still need to have at least one output in the transaction for it to be
583
583
// considered standard. We choose to go with an empty OP_RETURN as it is the cheapest
584
584
// way to include a dummy output.
585
- log_debug ! ( self . logger, "Including dummy OP_RETURN output since an output is needed and a change output was not provided" ) ;
586
- tx. output . push ( TxOut {
587
- value : Amount :: ZERO ,
588
- script_pubkey : ScriptBuf :: new_op_return ( & [ ] ) ,
589
- } ) ;
585
+ if tx. input . len ( ) <= 1 {
586
+ // Transactions have to be at least 65 bytes in non-witness data, which we can run
587
+ // under if we have too few witness inputs.
588
+ log_debug ! ( self . logger, "Including large OP_RETURN output since an output is needed and a change output was not provided and the transaction is small" ) ;
589
+ debug_assert ! ( !tx. input. is_empty( ) ) ;
590
+ tx. output . push ( TxOut {
591
+ value : Amount :: ZERO ,
592
+ // Minimum transaction size is 60 bytes, so we need a 5-byte script to get a
593
+ // 65 byte transaction. We do that as OP_RETURN <3 0 bytes, plus 1 byte len>.
594
+ script_pubkey : ScriptBuf :: new_op_return ( & [ 0 , 0 , 0 ] ) ,
595
+ } ) ;
596
+ debug_assert_eq ! ( tx. base_size( ) , 65 ) ;
597
+ } else {
598
+ log_debug ! ( self . logger, "Including dummy OP_RETURN output since an output is needed and a change output was not provided" ) ;
599
+ tx. output . push ( TxOut {
600
+ value : Amount :: ZERO ,
601
+ script_pubkey : ScriptBuf :: new_op_return ( & [ ] ) ,
602
+ } ) ;
603
+ }
590
604
}
591
605
}
592
606
@@ -603,85 +617,102 @@ where
603
617
let mut anchor_utxo = anchor_descriptor. previous_utxo ( ) ;
604
618
let commitment_tx_fee_sat = Amount :: from_sat ( commitment_tx_fee_sat) ;
605
619
anchor_utxo. value += commitment_tx_fee_sat;
606
- let must_spend = vec ! [ Input {
607
- outpoint: anchor_descriptor. outpoint,
608
- previous_utxo: anchor_utxo,
609
- satisfaction_weight: commitment_tx. weight( ) . to_wu( ) + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT ,
610
- } ] ;
611
- #[ cfg( debug_assertions) ]
612
- let must_spend_amount = must_spend. iter ( ) . map ( |input| input. previous_utxo . value ) . sum :: < Amount > ( ) ;
613
-
614
- log_debug ! ( self . logger, "Performing coin selection for commitment package (commitment and anchor transaction) targeting {} sat/kW" ,
615
- package_target_feerate_sat_per_1000_weight) ;
616
- let coin_selection: CoinSelection = self . utxo_source . select_confirmed_utxos (
617
- claim_id, must_spend, & [ ] , package_target_feerate_sat_per_1000_weight,
618
- ) ?;
619
-
620
- let mut anchor_tx = Transaction {
621
- version : Version :: TWO ,
622
- lock_time : LockTime :: ZERO , // TODO: Use next best height.
623
- input : vec ! [ anchor_descriptor. unsigned_tx_input( ) ] ,
624
- output : vec ! [ ] ,
625
- } ;
626
-
627
- #[ cfg( debug_assertions) ]
628
- let total_satisfaction_weight = ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT +
629
- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. satisfaction_weight ) . sum :: < u64 > ( ) ;
630
- #[ cfg( debug_assertions) ]
631
- let total_input_amount = must_spend_amount +
632
- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value ) . sum ( ) ;
633
-
634
- self . process_coin_selection ( & mut anchor_tx, & coin_selection) ;
635
- let anchor_txid = anchor_tx. compute_txid ( ) ;
620
+ let starting_package_and_fixed_input_satisfaction_weight =
621
+ commitment_tx. weight ( ) . to_wu ( ) + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT ;
622
+ let mut package_and_fixed_input_satisfaction_weight =
623
+ starting_package_and_fixed_input_satisfaction_weight;
624
+
625
+ loop {
626
+ let must_spend = vec ! [ Input {
627
+ outpoint: anchor_descriptor. outpoint,
628
+ previous_utxo: anchor_utxo. clone( ) ,
629
+ satisfaction_weight: package_and_fixed_input_satisfaction_weight,
630
+ } ] ;
631
+ let must_spend_amount = must_spend. iter ( ) . map ( |input| input. previous_utxo . value ) . sum :: < Amount > ( ) ;
632
+
633
+ log_debug ! ( self . logger, "Performing coin selection for commitment package (commitment and anchor transaction) targeting {} sat/kW" ,
634
+ package_target_feerate_sat_per_1000_weight) ;
635
+ let coin_selection: CoinSelection = self . utxo_source . select_confirmed_utxos (
636
+ claim_id, must_spend, & [ ] , package_target_feerate_sat_per_1000_weight,
637
+ ) ?;
638
+
639
+ let mut anchor_tx = Transaction {
640
+ version : Version :: TWO ,
641
+ lock_time : LockTime :: ZERO , // TODO: Use next best height.
642
+ input : vec ! [ anchor_descriptor. unsigned_tx_input( ) ] ,
643
+ output : vec ! [ ] ,
644
+ } ;
636
645
637
- // construct psbt
638
- let mut anchor_psbt = Psbt :: from_unsigned_tx ( anchor_tx) . unwrap ( ) ;
639
- // add witness_utxo to anchor input
640
- anchor_psbt. inputs [ 0 ] . witness_utxo = Some ( anchor_descriptor. previous_utxo ( ) ) ;
641
- // add witness_utxo to remaining inputs
642
- for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
643
- // add 1 to skip the anchor input
644
- let index = idx + 1 ;
645
- debug_assert_eq ! ( anchor_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
646
- if utxo. output . script_pubkey . is_witness_program ( ) {
647
- anchor_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
646
+ let total_satisfaction_weight = ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT +
647
+ coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. satisfaction_weight ) . sum :: < u64 > ( ) ;
648
+ let total_input_amount = must_spend_amount +
649
+ coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value ) . sum ( ) ;
650
+
651
+ self . process_coin_selection ( & mut anchor_tx, & coin_selection) ;
652
+ let anchor_txid = anchor_tx. compute_txid ( ) ;
653
+
654
+ // construct psbt
655
+ let mut anchor_psbt = Psbt :: from_unsigned_tx ( anchor_tx) . unwrap ( ) ;
656
+ // add witness_utxo to anchor input
657
+ anchor_psbt. inputs [ 0 ] . witness_utxo = Some ( anchor_descriptor. previous_utxo ( ) ) ;
658
+ // add witness_utxo to remaining inputs
659
+ for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
660
+ // add 1 to skip the anchor input
661
+ let index = idx + 1 ;
662
+ debug_assert_eq ! ( anchor_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
663
+ if utxo. output . script_pubkey . is_witness_program ( ) {
664
+ anchor_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
665
+ }
648
666
}
649
- }
650
-
651
- debug_assert_eq ! ( anchor_psbt. unsigned_tx. output. len( ) , 1 ) ;
652
- #[ cfg( debug_assertions) ]
653
- let unsigned_tx_weight = anchor_psbt. unsigned_tx . weight ( ) . to_wu ( ) - ( anchor_psbt. unsigned_tx . input . len ( ) as u64 * EMPTY_SCRIPT_SIG_WEIGHT ) ;
654
667
655
- log_debug ! ( self . logger , "Signing anchor transaction {}" , anchor_txid ) ;
656
- anchor_tx = self . utxo_source . sign_psbt ( anchor_psbt) ? ;
668
+ debug_assert_eq ! ( anchor_psbt . unsigned_tx . output . len ( ) , 1 ) ;
669
+ let unsigned_tx_weight = anchor_psbt . unsigned_tx . weight ( ) . to_wu ( ) - ( anchor_psbt. unsigned_tx . input . len ( ) as u64 * EMPTY_SCRIPT_SIG_WEIGHT ) ;
657
670
658
- let signer = anchor_descriptor. derive_channel_signer ( & self . signer_provider ) ;
659
- let anchor_sig = signer. sign_holder_anchor_input ( & anchor_tx, 0 , & self . secp ) ?;
660
- anchor_tx. input [ 0 ] . witness = anchor_descriptor. tx_input_witness ( & anchor_sig) ;
671
+ let package_fee = total_input_amount -
672
+ anchor_psbt. unsigned_tx . output . iter ( ) . map ( |output| output. value ) . sum ( ) ;
673
+ let package_weight = unsigned_tx_weight + 2 /* wit marker */ + total_satisfaction_weight + commitment_tx. weight ( ) . to_wu ( ) ;
674
+ if package_fee. to_sat ( ) * 1000 / package_weight < package_target_feerate_sat_per_1000_weight. into ( ) {
675
+ // On the first iteration of the loop, we may undershoot the target feerate because
676
+ // we had to add an OP_RETURN output in `process_coin_selection` which we didn't
677
+ // select sufficient coins for. Here we detect that case and go around again
678
+ // seeking additional weight.
679
+ if package_and_fixed_input_satisfaction_weight == starting_package_and_fixed_input_satisfaction_weight {
680
+ debug_assert ! ( anchor_psbt. unsigned_tx. output[ 0 ] . script_pubkey. is_op_return( ) ,
681
+ "Coin selection failed to select sufficient coins for its change output" ) ;
682
+ package_and_fixed_input_satisfaction_weight += anchor_psbt. unsigned_tx . output [ 0 ] . weight ( ) . to_wu ( ) ;
683
+ continue ;
684
+ } else {
685
+ debug_assert ! ( false , "Coin selection failed to select sufficient coins" ) ;
686
+ }
687
+ }
661
688
662
- #[ cfg( debug_assertions) ] {
663
- let signed_tx_weight = anchor_tx. weight ( ) . to_wu ( ) ;
664
- let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
665
- // Our estimate should be within a 1% error margin of the actual weight and we should
666
- // never underestimate.
667
- assert ! ( expected_signed_tx_weight >= signed_tx_weight &&
668
- expected_signed_tx_weight - ( expected_signed_tx_weight / 100 ) <= signed_tx_weight) ;
689
+ log_debug ! ( self . logger, "Signing anchor transaction {}" , anchor_txid) ;
690
+ anchor_tx = self . utxo_source . sign_psbt ( anchor_psbt) ?;
691
+
692
+ let signer = anchor_descriptor. derive_channel_signer ( & self . signer_provider ) ;
693
+ let anchor_sig = signer. sign_holder_anchor_input ( & anchor_tx, 0 , & self . secp ) ?;
694
+ anchor_tx. input [ 0 ] . witness = anchor_descriptor. tx_input_witness ( & anchor_sig) ;
695
+
696
+ #[ cfg( debug_assertions) ] {
697
+ let signed_tx_weight = anchor_tx. weight ( ) . to_wu ( ) ;
698
+ let expected_signed_tx_weight = unsigned_tx_weight + 2 /* wit marker */ + total_satisfaction_weight;
699
+ // Our estimate should be within a 1% error margin of the actual weight and we should
700
+ // never underestimate.
701
+ assert ! ( expected_signed_tx_weight >= signed_tx_weight &&
702
+ expected_signed_tx_weight - ( expected_signed_tx_weight / 100 ) <= signed_tx_weight) ;
703
+
704
+ let expected_package_fee = Amount :: from_sat ( fee_for_weight ( package_target_feerate_sat_per_1000_weight,
705
+ signed_tx_weight + commitment_tx. weight ( ) . to_wu ( ) ) ) ;
706
+ // Our feerate should always be at least what we were seeking. It may overshoot if
707
+ // the coin selector burned funds to an OP_RETURN without a change output.
708
+ assert ! ( package_fee >= expected_package_fee) ;
709
+ }
669
710
670
- let expected_package_fee = Amount :: from_sat ( fee_for_weight ( package_target_feerate_sat_per_1000_weight,
671
- signed_tx_weight + commitment_tx. weight ( ) . to_wu ( ) ) ) ;
672
- let package_fee = total_input_amount -
673
- anchor_tx. output . iter ( ) . map ( |output| output. value ) . sum ( ) ;
674
- // Our fee should be within a 5% error margin of the expected fee based on the
675
- // feerate and transaction weight and we should never pay less than required.
676
- let fee_error_margin = expected_package_fee * 5 / 100 ;
677
- assert ! ( package_fee >= expected_package_fee &&
678
- package_fee - fee_error_margin <= expected_package_fee) ;
711
+ log_info ! ( self . logger, "Broadcasting anchor transaction {} to bump channel close with txid {}" ,
712
+ anchor_txid, commitment_tx. compute_txid( ) ) ;
713
+ self . broadcaster . broadcast_transactions ( & [ & commitment_tx, & anchor_tx] ) ;
714
+ return Ok ( ( ) ) ;
679
715
}
680
-
681
- log_info ! ( self . logger, "Broadcasting anchor transaction {} to bump channel close with txid {}" ,
682
- anchor_txid, commitment_tx. compute_txid( ) ) ;
683
- self . broadcaster . broadcast_transactions ( & [ & commitment_tx, & anchor_tx] ) ;
684
- Ok ( ( ) )
685
716
}
686
717
687
718
/// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a
@@ -778,11 +809,9 @@ where
778
809
let expected_signed_tx_fee = fee_for_weight ( target_feerate_sat_per_1000_weight, signed_tx_weight) ;
779
810
let signed_tx_fee = total_input_amount -
780
811
htlc_tx. output . iter ( ) . map ( |output| output. value . to_sat ( ) ) . sum :: < u64 > ( ) ;
781
- // Our fee should be within a 5% error margin of the expected fee based on the
782
- // feerate and transaction weight and we should never pay less than required.
783
- let fee_error_margin = expected_signed_tx_fee * 5 / 100 ;
784
- assert ! ( signed_tx_fee >= expected_signed_tx_fee &&
785
- signed_tx_fee - fee_error_margin <= expected_signed_tx_fee) ;
812
+ // Our feerate should always be at least what we were seeking. It may overshoot if
813
+ // the coin selector burned funds to an OP_RETURN without a change output.
814
+ assert ! ( signed_tx_fee >= expected_signed_tx_fee) ;
786
815
}
787
816
788
817
log_info ! ( self . logger, "Broadcasting {}" , log_tx!( htlc_tx) ) ;
@@ -822,3 +851,116 @@ where
822
851
}
823
852
}
824
853
}
854
+
855
+ #[ cfg( test) ]
856
+ mod tests {
857
+ use super :: * ;
858
+
859
+ use crate :: io:: Cursor ;
860
+ use crate :: ln:: chan_utils:: ChannelTransactionParameters ;
861
+ use crate :: util:: ser:: Readable ;
862
+ use crate :: util:: test_utils:: { TestBroadcaster , TestLogger } ;
863
+ use crate :: sign:: KeysManager ;
864
+
865
+ use bitcoin:: hashes:: Hash ;
866
+ use bitcoin:: hex:: FromHex ;
867
+ use bitcoin:: { Network , ScriptBuf , Transaction , Txid } ;
868
+
869
+ struct TestCoinSelectionSource {
870
+ // (commitment + anchor value, commitment + input weight, target feerate, result)
871
+ expected_selects : Mutex < Vec < ( u64 , u64 , u32 , CoinSelection ) > > ,
872
+ }
873
+ impl CoinSelectionSource for TestCoinSelectionSource {
874
+ fn select_confirmed_utxos (
875
+ & self ,
876
+ _claim_id : ClaimId ,
877
+ must_spend : Vec < Input > ,
878
+ _must_pay_to : & [ TxOut ] ,
879
+ target_feerate_sat_per_1000_weight : u32
880
+ ) -> Result < CoinSelection , ( ) > {
881
+ let mut expected_selects = self . expected_selects . lock ( ) . unwrap ( ) ;
882
+ let ( weight, value, feerate, res) = expected_selects. remove ( 0 ) ;
883
+ assert_eq ! ( must_spend. len( ) , 1 ) ;
884
+ assert_eq ! ( must_spend[ 0 ] . satisfaction_weight, weight) ;
885
+ assert_eq ! ( must_spend[ 0 ] . previous_utxo. value. to_sat( ) , value) ;
886
+ assert_eq ! ( target_feerate_sat_per_1000_weight, feerate) ;
887
+ Ok ( res)
888
+ }
889
+ fn sign_psbt ( & self , psbt : Psbt ) -> Result < Transaction , ( ) > {
890
+ let mut tx = psbt. unsigned_tx ;
891
+ for input in tx. input . iter_mut ( ) {
892
+ if input. previous_output . txid != Txid :: from_byte_array ( [ 44 ; 32 ] ) {
893
+ // Channel output, add a realistic size witness to make the assertions happy
894
+ input. witness = Witness :: from_slice ( & [ vec ! [ 42 ; 162 ] ] ) ;
895
+ }
896
+ }
897
+ Ok ( tx)
898
+ }
899
+ }
900
+
901
+ impl Drop for TestCoinSelectionSource {
902
+ fn drop ( & mut self ) {
903
+ assert ! ( self . expected_selects. lock( ) . unwrap( ) . is_empty( ) ) ;
904
+ }
905
+ }
906
+
907
+ #[ test]
908
+ fn test_op_return_under_funds ( ) {
909
+ // Test what happens if we have to select coins but the anchor output value itself suffices
910
+ // to pay the required fee.
911
+ //
912
+ // This tests a case that occurred on mainnet (with the below transaction) where the target
913
+ // feerate (of 868 sat/kW) was met by the anchor output's 330 sats alone. This caused the
914
+ // use of an OP_RETURN which created a transaction which, at the time, was less than 64
915
+ // bytes long (the current code generates a 65 byte transaction instead to meet
916
+ // standardness rule). It also tests the handling of selection failure where we selected
917
+ // coins which were insufficient once the OP_RETURN output was added, causing us to need to
918
+ // select coins again with additional weight.
919
+
920
+ // Tx 18032ad172a5f28fa6e16392d6cc57ea47895781434ce15d03766cc47a955fb9
921
+ let commitment_tx_bytes = Vec :: < u8 > :: from_hex ( "02000000000101cc6b0a9dd84b52c07340fff6fab002fc37b4bdccfdce9f39c5ec8391a56b652907000000009b948b80044a01000000000000220020b4182433fdfdfbf894897c98f84d92cec815cee222755ffd000ae091c9dadc2d4a01000000000000220020f83f7dbf90e2de325b5bb6bab0ae370151278c6964739242b2e7ce0cb68a5d81cb4a02000000000022002024add256b3dccee772610caef82a601045ab6f98fd6d5df608cc756b891ccfe63ffa490000000000220020894bf32b37906a643625e87131897c3714c71b3ac9b161862c9aa6c8d468b4c70400473044022060abd347bff2cca0212b660e6addff792b3356bd4a1b5b26672dc2e694c3c5f002202b40b7e346b494a7b1d048b4ec33ba99c90a09ab48eb1df64ccdc768066c865c014730440220554d8361e04dc0ee178dcb23d2d23f53ec7a1ae4312a5be76bd9e83ab8981f3d0220501f23ffb18cb81ccea72d30252f88d5e69fd28ba4992803d03c00d06fa8899e0147522102817f6ce189ab7114f89e8d5df58cdbbaf272dc8e71b92982d47456a0b6a0ceee2102c9b4d2f24aca54f65e13f4c83e2a8d8e877e12d3c71a76e81f28a5cabc652aa352ae626c7620" ) . unwrap ( ) ;
922
+ let commitment_tx: Transaction = Readable :: read ( & mut Cursor :: new ( & commitment_tx_bytes) ) . unwrap ( ) ;
923
+ let total_commitment_weight = commitment_tx. weight ( ) . to_wu ( ) + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT ;
924
+ let commitment_and_anchor_fee = 930 + 330 ;
925
+ let op_return_weight = TxOut {
926
+ value : Amount :: ZERO ,
927
+ script_pubkey : ScriptBuf :: new_op_return ( & [ 0 ; 3 ] ) ,
928
+ } . weight ( ) . to_wu ( ) ;
929
+
930
+ let broadcaster = TestBroadcaster :: new ( Network :: Testnet ) ;
931
+ let source = TestCoinSelectionSource {
932
+ expected_selects : Mutex :: new ( vec ! [
933
+ ( total_commitment_weight, commitment_and_anchor_fee, 868 , CoinSelection { confirmed_utxos: Vec :: new( ) , change_output: None } ) ,
934
+ ( total_commitment_weight + op_return_weight, commitment_and_anchor_fee, 868 , CoinSelection {
935
+ confirmed_utxos: vec![ Utxo {
936
+ outpoint: OutPoint { txid: Txid :: from_byte_array( [ 44 ; 32 ] ) , vout: 0 } ,
937
+ output: TxOut { value: Amount :: from_sat( 200 ) , script_pubkey: ScriptBuf :: new( ) } ,
938
+ satisfaction_weight: 5 , // Just the script_sig and witness lengths
939
+ } ] ,
940
+ change_output: None ,
941
+ } )
942
+ ] ) ,
943
+ } ;
944
+ let signer = KeysManager :: new ( & [ 42 ; 32 ] , 42 , 42 ) ;
945
+ let logger = TestLogger :: new ( ) ;
946
+ let handler = BumpTransactionEventHandler :: new ( & broadcaster, & source, & signer, & logger) ;
947
+
948
+ handler. handle_event ( & BumpTransactionEvent :: ChannelClose {
949
+ channel_id : ChannelId ( [ 42 ; 32 ] ) ,
950
+ counterparty_node_id : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
951
+ claim_id : ClaimId ( [ 42 ; 32 ] ) ,
952
+ package_target_feerate_sat_per_1000_weight : 868 ,
953
+ commitment_tx_fee_satoshis : 930 ,
954
+ commitment_tx,
955
+ anchor_descriptor : AnchorDescriptor {
956
+ channel_derivation_parameters : ChannelDerivationParameters {
957
+ value_satoshis : 42_000_000 ,
958
+ keys_id : [ 42 ; 32 ] ,
959
+ transaction_parameters : ChannelTransactionParameters :: test_dummy ( ) ,
960
+ } ,
961
+ outpoint : OutPoint { txid : Txid :: from_byte_array ( [ 42 ; 32 ] ) , vout : 0 } ,
962
+ } ,
963
+ pending_htlcs : Vec :: new ( ) ,
964
+ } ) ;
965
+ }
966
+ }
0 commit comments