@@ -41,6 +41,8 @@ use crate::util::logger::Logger;
4141use bitcoin:: amount:: Amount ;
4242use bitcoin:: consensus:: Encodable ;
4343use bitcoin:: constants:: WITNESS_SCALE_FACTOR ;
44+ use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
45+ use bitcoin:: hashes:: { Hash , HashEngine } ;
4446use bitcoin:: locktime:: absolute:: LockTime ;
4547use bitcoin:: secp256k1;
4648use bitcoin:: secp256k1:: ecdsa:: Signature ;
@@ -847,24 +849,13 @@ where
847849 /// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a
848850 /// fully-signed, fee-bumped HTLC transaction that is broadcast to the network.
849851 async fn handle_htlc_resolution (
850- & self , claim_id : ClaimId , target_feerate_sat_per_1000_weight : u32 ,
851- htlc_descriptors : & [ HTLCDescriptor ] , tx_lock_time : LockTime ,
852+ & self , target_feerate_sat_per_1000_weight : u32 , htlc_descriptors : & [ HTLCDescriptor ] ,
853+ tx_lock_time : LockTime ,
852854 ) -> Result < ( ) , ( ) > {
853855 let channel_type = & htlc_descriptors[ 0 ]
854856 . channel_derivation_parameters
855857 . transaction_parameters
856858 . channel_type_features ;
857- let mut htlc_tx = Transaction {
858- version : if channel_type. supports_anchor_zero_fee_commitments ( ) {
859- Version :: non_standard ( 3 )
860- } else {
861- Version :: TWO
862- } ,
863- lock_time : tx_lock_time,
864- input : vec ! [ ] ,
865- output : vec ! [ ] ,
866- } ;
867- let mut must_spend = Vec :: with_capacity ( htlc_descriptors. len ( ) ) ;
868859 let ( htlc_success_witness_weight, htlc_timeout_witness_weight) =
869860 if channel_type. supports_anchor_zero_fee_commitments ( ) {
870861 (
@@ -879,123 +870,181 @@ where
879870 } else {
880871 panic ! ( "channel type should be either zero-fee HTLCs, or zero-fee commitments" ) ;
881872 } ;
882- for htlc_descriptor in htlc_descriptors {
883- let htlc_input = htlc_descriptor. unsigned_tx_input ( ) ;
884- must_spend. push ( Input {
885- outpoint : htlc_input. previous_output . clone ( ) ,
886- previous_utxo : htlc_descriptor. previous_utxo ( & self . secp ) ,
887- satisfaction_weight : EMPTY_SCRIPT_SIG_WEIGHT
888- + if htlc_descriptor. preimage . is_some ( ) {
889- htlc_success_witness_weight
890- } else {
891- htlc_timeout_witness_weight
892- } ,
893- } ) ;
894- htlc_tx. input . push ( htlc_input) ;
895- let htlc_output = htlc_descriptor. tx_output ( & self . secp ) ;
896- htlc_tx. output . push ( htlc_output) ;
897- }
898873
899- log_debug ! (
900- self . logger,
901- "Performing coin selection for HTLC transaction targeting {} sat/kW" ,
902- target_feerate_sat_per_1000_weight
903- ) ;
874+ let max_weight = if channel_type. supports_anchor_zero_fee_commitments ( ) {
875+ // Cap the size of transactions claiming `HolderHTLCOutput` in 0FC channels.
876+ // Otherwise, we could hit the max 10_000vB size limit on V3 transactions
877+ // (BIP 431 rule 4).
878+ chan_utils:: TRUC_MAX_WEIGHT
879+ } else {
880+ u64:: MAX
881+ } ;
882+ let mut broadcasted_htlcs = 0 ;
883+ let mut batch_size = htlc_descriptors. len ( ) - broadcasted_htlcs;
884+
885+ while broadcasted_htlcs < htlc_descriptors. len ( ) {
886+ let htlcs = & htlc_descriptors[ broadcasted_htlcs..broadcasted_htlcs + batch_size] ;
887+ // Generate a new claim_id to map a user-provided utxo to this
888+ // particular set of HTLCs via `select_confirmed_utxos`.
889+ //
890+ // This matches the scheme used in `onchaintx.rs`, so for non-0fc-channels,
891+ // this should match the `ClaimId` of the claim generated in `onchaintx.rs`.
892+ let mut engine = Sha256 :: engine ( ) ;
893+ for htlc in htlcs {
894+ engine. input ( & htlc. commitment_txid . to_byte_array ( ) ) ;
895+ engine. input ( & htlc. htlc . transaction_output_index . unwrap ( ) . to_be_bytes ( ) ) ;
896+ }
897+ let utxo_id = ClaimId ( Sha256 :: from_engine ( engine) . to_byte_array ( ) ) ;
898+ log_info ! (
899+ self . logger,
900+ "Batch transaction assigned to UTXO id {} contains {} HTLCs: {}" ,
901+ log_bytes!( utxo_id. 0 ) ,
902+ htlcs. len( ) ,
903+ log_iter!( htlcs. iter( ) . map( |d| d. outpoint( ) ) )
904+ ) ;
905+ let mut htlc_tx = Transaction {
906+ version : if channel_type. supports_anchor_zero_fee_commitments ( ) {
907+ Version :: non_standard ( 3 )
908+ } else {
909+ Version :: TWO
910+ } ,
911+ lock_time : tx_lock_time,
912+ input : vec ! [ ] ,
913+ output : vec ! [ ] ,
914+ } ;
915+ let mut must_spend = Vec :: with_capacity ( htlcs. len ( ) ) ;
916+ for htlc_descriptor in htlcs {
917+ let htlc_input = htlc_descriptor. unsigned_tx_input ( ) ;
918+ must_spend. push ( Input {
919+ outpoint : htlc_input. previous_output . clone ( ) ,
920+ previous_utxo : htlc_descriptor. previous_utxo ( & self . secp ) ,
921+ satisfaction_weight : EMPTY_SCRIPT_SIG_WEIGHT
922+ + if htlc_descriptor. preimage . is_some ( ) {
923+ htlc_success_witness_weight
924+ } else {
925+ htlc_timeout_witness_weight
926+ } ,
927+ } ) ;
928+ htlc_tx. input . push ( htlc_input) ;
929+ let htlc_output = htlc_descriptor. tx_output ( & self . secp ) ;
930+ htlc_tx. output . push ( htlc_output) ;
931+ }
904932
905- #[ cfg( debug_assertions) ]
906- let must_spend_satisfaction_weight =
907- must_spend. iter ( ) . map ( |input| input. satisfaction_weight ) . sum :: < u64 > ( ) ;
908- #[ cfg( debug_assertions) ]
909- let must_spend_amount =
910- must_spend. iter ( ) . map ( |input| input. previous_utxo . value . to_sat ( ) ) . sum :: < u64 > ( ) ;
933+ log_debug ! (
934+ self . logger,
935+ "Performing coin selection for HTLC transaction targeting {} sat/kW" ,
936+ target_feerate_sat_per_1000_weight
937+ ) ;
911938
912- let coin_selection: CoinSelection = self
913- . utxo_source
914- . select_confirmed_utxos (
915- claim_id,
916- must_spend,
917- & htlc_tx. output ,
918- target_feerate_sat_per_1000_weight,
919- )
920- . await ?;
921-
922- #[ cfg( debug_assertions) ]
923- let input_satisfaction_weight: u64 =
924- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. satisfaction_weight ) . sum ( ) ;
925- #[ cfg( debug_assertions) ]
926- let total_satisfaction_weight = must_spend_satisfaction_weight + input_satisfaction_weight;
927- #[ cfg( debug_assertions) ]
928- let input_value: u64 =
929- coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value . to_sat ( ) ) . sum ( ) ;
930- #[ cfg( debug_assertions) ]
931- let total_input_amount = must_spend_amount + input_value;
932-
933- self . process_coin_selection ( & mut htlc_tx, & coin_selection) ;
934-
935- // construct psbt
936- let mut htlc_psbt = Psbt :: from_unsigned_tx ( htlc_tx) . unwrap ( ) ;
937- // add witness_utxo to htlc inputs
938- for ( i, htlc_descriptor) in htlc_descriptors. iter ( ) . enumerate ( ) {
939- debug_assert_eq ! (
940- htlc_psbt. unsigned_tx. input[ i] . previous_output,
941- htlc_descriptor. outpoint( )
939+ let must_spend_satisfaction_weight =
940+ must_spend. iter ( ) . map ( |input| input. satisfaction_weight ) . sum :: < u64 > ( ) ;
941+ #[ cfg( debug_assertions) ]
942+ let must_spend_amount =
943+ must_spend. iter ( ) . map ( |input| input. previous_utxo . value . to_sat ( ) ) . sum :: < u64 > ( ) ;
944+
945+ let coin_selection: CoinSelection = self
946+ . utxo_source
947+ . select_confirmed_utxos (
948+ utxo_id,
949+ must_spend,
950+ & htlc_tx. output ,
951+ target_feerate_sat_per_1000_weight,
952+ )
953+ . await ?;
954+
955+ let input_satisfaction_weight: u64 =
956+ coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. satisfaction_weight ) . sum ( ) ;
957+ let total_satisfaction_weight =
958+ must_spend_satisfaction_weight + input_satisfaction_weight;
959+
960+ #[ cfg( debug_assertions) ]
961+ let input_value: u64 =
962+ coin_selection. confirmed_utxos . iter ( ) . map ( |utxo| utxo. output . value . to_sat ( ) ) . sum ( ) ;
963+ #[ cfg( debug_assertions) ]
964+ let total_input_amount = must_spend_amount + input_value;
965+
966+ self . process_coin_selection ( & mut htlc_tx, & coin_selection) ;
967+
968+ let unsigned_tx_weight =
969+ htlc_tx. weight ( ) . to_wu ( ) - ( htlc_tx. input . len ( ) as u64 * EMPTY_SCRIPT_SIG_WEIGHT ) ;
970+ let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
971+ if expected_signed_tx_weight >= max_weight {
972+ let extra_weight = expected_signed_tx_weight - max_weight;
973+ let htlcs_to_remove = ( extra_weight / chan_utils:: htlc_timeout_tx_weight ( channel_type)
974+ // If we remove extra_weight / timeout_weight + 1 we sometimes still land above max_weight
975+ + 2 ) as usize ;
976+ batch_size = batch_size. checked_sub ( htlcs_to_remove) . ok_or ( ( ) ) ?;
977+ continue ;
978+ }
979+ broadcasted_htlcs += batch_size;
980+ batch_size = htlc_descriptors. len ( ) - broadcasted_htlcs;
981+
982+ // construct psbt
983+ let mut htlc_psbt = Psbt :: from_unsigned_tx ( htlc_tx) . unwrap ( ) ;
984+ // add witness_utxo to htlc inputs
985+ for ( i, htlc_descriptor) in htlcs. iter ( ) . enumerate ( ) {
986+ debug_assert_eq ! (
987+ htlc_psbt. unsigned_tx. input[ i] . previous_output,
988+ htlc_descriptor. outpoint( )
989+ ) ;
990+ htlc_psbt. inputs [ i] . witness_utxo = Some ( htlc_descriptor. previous_utxo ( & self . secp ) ) ;
991+ }
992+
993+ // add witness_utxo to remaining inputs
994+ for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
995+ // offset to skip the htlc inputs
996+ let index = idx + htlcs. len ( ) ;
997+ debug_assert_eq ! ( htlc_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
998+ if utxo. output . script_pubkey . is_witness_program ( ) {
999+ htlc_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
1000+ }
1001+ }
1002+
1003+ log_debug ! (
1004+ self . logger,
1005+ "Signing HTLC transaction {}" ,
1006+ htlc_psbt. unsigned_tx. compute_txid( )
9421007 ) ;
943- htlc_psbt. inputs [ i] . witness_utxo = Some ( htlc_descriptor. previous_utxo ( & self . secp ) ) ;
944- }
945- // add witness_utxo to remaining inputs
946- for ( idx, utxo) in coin_selection. confirmed_utxos . into_iter ( ) . enumerate ( ) {
947- // offset to skip the htlc inputs
948- let index = idx + htlc_descriptors. len ( ) ;
949- debug_assert_eq ! ( htlc_psbt. unsigned_tx. input[ index] . previous_output, utxo. outpoint) ;
950- if utxo. output . script_pubkey . is_witness_program ( ) {
951- htlc_psbt. inputs [ index] . witness_utxo = Some ( utxo. output ) ;
1008+ let mut htlc_tx = self . utxo_source . sign_psbt ( htlc_psbt) . await ?;
1009+
1010+ let mut signers = BTreeMap :: new ( ) ;
1011+ for ( idx, htlc_descriptor) in htlcs. iter ( ) . enumerate ( ) {
1012+ let keys_id = htlc_descriptor. channel_derivation_parameters . keys_id ;
1013+ let signer = signers
1014+ . entry ( keys_id)
1015+ . or_insert_with ( || self . signer_provider . derive_channel_signer ( keys_id) ) ;
1016+ let htlc_sig = signer. sign_holder_htlc_transaction (
1017+ & htlc_tx,
1018+ idx,
1019+ htlc_descriptor,
1020+ & self . secp ,
1021+ ) ?;
1022+ let witness_script = htlc_descriptor. witness_script ( & self . secp ) ;
1023+ htlc_tx. input [ idx] . witness =
1024+ htlc_descriptor. tx_input_witness ( & htlc_sig, & witness_script) ;
9521025 }
953- }
9541026
955- #[ cfg( debug_assertions) ]
956- let unsigned_tx_weight = htlc_psbt. unsigned_tx . weight ( ) . to_wu ( )
957- - ( htlc_psbt. unsigned_tx . input . len ( ) as u64 * EMPTY_SCRIPT_SIG_WEIGHT ) ;
1027+ #[ cfg( debug_assertions) ]
1028+ {
1029+ let signed_tx_weight = htlc_tx. weight ( ) . to_wu ( ) ;
1030+ // Our estimate should be within a 2% error margin of the actual weight and we should
1031+ // never underestimate.
1032+ assert ! ( expected_signed_tx_weight >= signed_tx_weight) ;
1033+ assert ! ( expected_signed_tx_weight * 98 / 100 <= signed_tx_weight) ;
9581034
959- log_debug ! (
960- self . logger,
961- "Signing HTLC transaction {}" ,
962- htlc_psbt. unsigned_tx. compute_txid( )
963- ) ;
964- htlc_tx = self . utxo_source . sign_psbt ( htlc_psbt) . await ?;
965-
966- let mut signers = BTreeMap :: new ( ) ;
967- for ( idx, htlc_descriptor) in htlc_descriptors. iter ( ) . enumerate ( ) {
968- let keys_id = htlc_descriptor. channel_derivation_parameters . keys_id ;
969- let signer = signers
970- . entry ( keys_id)
971- . or_insert_with ( || self . signer_provider . derive_channel_signer ( keys_id) ) ;
972- let htlc_sig =
973- signer. sign_holder_htlc_transaction ( & htlc_tx, idx, htlc_descriptor, & self . secp ) ?;
974- let witness_script = htlc_descriptor. witness_script ( & self . secp ) ;
975- htlc_tx. input [ idx] . witness =
976- htlc_descriptor. tx_input_witness ( & htlc_sig, & witness_script) ;
977- }
1035+ let expected_signed_tx_fee =
1036+ fee_for_weight ( target_feerate_sat_per_1000_weight, signed_tx_weight) ;
1037+ let signed_tx_fee = total_input_amount
1038+ - htlc_tx. output . iter ( ) . map ( |output| output. value . to_sat ( ) ) . sum :: < u64 > ( ) ;
1039+ // Our feerate should always be at least what we were seeking. It may overshoot if
1040+ // the coin selector burned funds to an OP_RETURN without a change output.
1041+ assert ! ( signed_tx_fee >= expected_signed_tx_fee) ;
1042+ }
9781043
979- #[ cfg( debug_assertions) ]
980- {
981- let signed_tx_weight = htlc_tx. weight ( ) . to_wu ( ) ;
982- let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
983- // Our estimate should be within a 1% error margin of the actual weight and we should
984- // never underestimate.
985- assert ! ( expected_signed_tx_weight >= signed_tx_weight) ;
986- assert ! ( expected_signed_tx_weight * 99 / 100 <= signed_tx_weight) ;
987-
988- let expected_signed_tx_fee =
989- fee_for_weight ( target_feerate_sat_per_1000_weight, signed_tx_weight) ;
990- let signed_tx_fee = total_input_amount
991- - htlc_tx. output . iter ( ) . map ( |output| output. value . to_sat ( ) ) . sum :: < u64 > ( ) ;
992- // Our feerate should always be at least what we were seeking. It may overshoot if
993- // the coin selector burned funds to an OP_RETURN without a change output.
994- assert ! ( signed_tx_fee >= expected_signed_tx_fee) ;
1044+ log_info ! ( self . logger, "Broadcasting {}" , log_tx!( htlc_tx) ) ;
1045+ self . broadcaster . broadcast_transactions ( & [ & htlc_tx] ) ;
9951046 }
9961047
997- log_info ! ( self . logger, "Broadcasting {}" , log_tx!( htlc_tx) ) ;
998- self . broadcaster . broadcast_transactions ( & [ & htlc_tx] ) ;
9991048 Ok ( ( ) )
10001049 }
10011050
@@ -1046,7 +1095,6 @@ where
10461095 log_iter!( htlc_descriptors. iter( ) . map( |d| d. outpoint( ) ) )
10471096 ) ;
10481097 self . handle_htlc_resolution (
1049- * claim_id,
10501098 * target_feerate_sat_per_1000_weight,
10511099 htlc_descriptors,
10521100 * tx_lock_time,
0 commit comments