@@ -4252,12 +4252,14 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
42524252 cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
42534253}
42544254
4255+ /// Determine whether with our given inputs, outputs, and intended contribution
4256+ /// a change output should be added or not, and if so, of waht size
42554257#[allow(dead_code)] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
42564258fn need_to_add_funding_change_output(is_initiator: bool,
4257- our_funding_satoshis : u64, funding_inputs_prev_outputs: &Vec<TxOut> ,
4258- funding_outputs : &Vec<OutputOwned >, funding_feerate_sat_per_1000_weight: u32 ,
4259- holder_dust_limit_satoshis: u64,
4260- ) -> Result< Option<u64>, ChannelError > {
4259+ our_contribution : u64,
4260+ funding_inputs_prev_outputs : &Vec<TxOut >, funding_outputs: &Vec<OutputOwned> ,
4261+ funding_feerate_sat_per_1000_weight: u32, holder_dust_limit_satoshis: u64,
4262+ ) -> Option<u64> {
42614263 let our_funding_inputs_weight = funding_inputs_prev_outputs.iter().fold(0u64, |weight, prev_output| {
42624264 weight.saturating_add(estimate_input_weight(prev_output).to_wu())
42634265 });
@@ -4276,13 +4278,13 @@ fn need_to_add_funding_change_output(is_initiator: bool,
42764278 let total_input_satoshis: u64 = funding_inputs_prev_outputs.iter().map(|out| out.value.to_sat()).sum();
42774279
42784280 let remaining_value = total_input_satoshis
4279- .saturating_sub(our_funding_satoshis )
4281+ .saturating_sub(our_contribution )
42804282 .saturating_sub(fees_sats);
42814283
4282- if remaining_value < holder_dust_limit_satoshis {
4283- Ok( None)
4284+ if remaining_value <= holder_dust_limit_satoshis {
4285+ None
42844286 } else {
4285- Ok( Some(remaining_value) )
4287+ Some(remaining_value)
42864288 }
42874289}
42884290
@@ -4295,7 +4297,7 @@ fn maybe_add_funding_change_output<SP: Deref>(signer_provider: &SP, is_initiator
42954297 let remaining_value = match need_to_add_funding_change_output(
42964298 is_initiator, our_funding_satoshis, funding_inputs_prev_outputs,
42974299 funding_outputs, funding_feerate_sat_per_1000_weight, holder_dust_limit_satoshis
4298- )? {
4300+ ) {
42994301 None => {
43004302 // No need to add
43014303 return Ok(None);
@@ -12094,44 +12096,81 @@ mod tests {
1209412096 }
1209512097
1209612098 #[test]
12097- fn test_need_to_add_funding_change_output () {
12098- let prevouts = vec![
12099+ fn test_need_to_add_funding_change_output_open () {
12100+ let input_prevouts = vec![
1209912101 TxOut { value: Amount::from_sat(70_000), script_pubkey: ScriptBuf::new()},
1210012102 TxOut { value: Amount::from_sat(60_000), script_pubkey: ScriptBuf::new()},
1210112103 ];
12102- let txout = TxOut { value: Amount::from_sat(125_000), script_pubkey: ScriptBuf::new()};
12103- let outputs = vec![OutputOwned::Shared(SharedOwnedOutput::new(txout, 105_000))];
1210412104 let our_contributed = 110_000;
12105+ let txout = TxOut { value: Amount::from_sat(128_000), script_pubkey: ScriptBuf::new()};
12106+ let outputs = vec![OutputOwned::SharedControlFullyOwned(txout)];
1210512107 let funding_feerate_sat_per_1000_weight = 3000;
1210612108
12107- let total_inputs: u64 = prevouts .iter().map(|o| o.value.to_sat()).sum();
12109+ let total_inputs: u64 = input_prevouts .iter().map(|o| o.value.to_sat()).sum();
1210812110 let gross_change = total_inputs - our_contributed;
1210912111 let fees = 1746;
1211012112 let common_fees = 126;
1211112113 {
1211212114 // There is leftover for change
12113- let res = need_to_add_funding_change_output(true, our_contributed, &prevouts , &outputs, funding_feerate_sat_per_1000_weight, 300);
12114- assert_eq!(res.unwrap().unwrap() , gross_change - fees - common_fees);
12115+ let res = need_to_add_funding_change_output(true, our_contributed, &input_prevouts , &outputs, funding_feerate_sat_per_1000_weight, 300);
12116+ assert_eq!(res.unwrap(), gross_change - fees - common_fees);
1211512117 }
1211612118 {
1211712119 // There is leftover for change, without common fees
12118- let res = need_to_add_funding_change_output(false, our_contributed, &prevouts, &outputs, funding_feerate_sat_per_1000_weight, 300);
12119- assert_eq!(res.unwrap().unwrap(), gross_change - fees);
12120+ let res = need_to_add_funding_change_output(false, our_contributed, &input_prevouts, &outputs, funding_feerate_sat_per_1000_weight, 300);
12121+ assert_eq!(res.unwrap(), gross_change - fees);
12122+ }
12123+ {
12124+ // Larger fee, smaller change
12125+ let res = need_to_add_funding_change_output(true, our_contributed, &input_prevouts, &outputs, 9000, 300);
12126+ assert_eq!(res.unwrap(), 14384);
1212012127 }
1212112128 {
1212212129 // Insufficient inputs, no leftover
12123- let res = need_to_add_funding_change_output(false, 130_000, &prevouts, &outputs, funding_feerate_sat_per_1000_weight, 300);
12124- assert!(res.unwrap().is_none());
12130+ let res = need_to_add_funding_change_output(false, 130_000, &input_prevouts, &outputs, funding_feerate_sat_per_1000_weight, 300);
12131+ assert!(res.is_none());
12132+ }
12133+ {
12134+ // Very small leftover
12135+ let res = need_to_add_funding_change_output(false, 128_100, &input_prevouts, &outputs, funding_feerate_sat_per_1000_weight, 300);
12136+ assert!(res.is_none());
12137+ }
12138+ {
12139+ // Small leftover, but not dust
12140+ let res = need_to_add_funding_change_output(false, 128_100, &input_prevouts, &outputs, funding_feerate_sat_per_1000_weight, 100);
12141+ assert_eq!(res.unwrap(), 154);
12142+ }
12143+ }
12144+
12145+ #[test]
12146+ fn test_need_to_add_funding_change_output_splice() {
12147+ let input_prevouts = vec![
12148+ TxOut { value: Amount::from_sat(70_000), script_pubkey: ScriptBuf::new()},
12149+ TxOut { value: Amount::from_sat(60_000), script_pubkey: ScriptBuf::new()},
12150+ ];
12151+ let our_contributed = 110_000;
12152+ let txout = TxOut { value: Amount::from_sat(148_000), script_pubkey: ScriptBuf::new()};
12153+ let outputs = vec![OutputOwned::Shared(SharedOwnedOutput::new(txout, our_contributed))];
12154+ let funding_feerate_sat_per_1000_weight = 3000;
12155+
12156+ let total_inputs: u64 = input_prevouts.iter().map(|o| o.value.to_sat()).sum();
12157+ let gross_change = total_inputs - our_contributed;
12158+ let fees = 1746;
12159+ let common_fees = 126;
12160+ {
12161+ // There is leftover for change
12162+ let res = need_to_add_funding_change_output(true, our_contributed, &input_prevouts, &outputs, funding_feerate_sat_per_1000_weight, 300);
12163+ assert_eq!(res.unwrap(), gross_change - fees - common_fees);
1212512164 }
1212612165 {
1212712166 // Very small leftover
12128- let res = need_to_add_funding_change_output(false, 128_100, &prevouts , &outputs, funding_feerate_sat_per_1000_weight, 300);
12129- assert!(res.unwrap(). is_none());
12167+ let res = need_to_add_funding_change_output(false, 128_100, &input_prevouts , &outputs, funding_feerate_sat_per_1000_weight, 300);
12168+ assert!(res.is_none());
1213012169 }
1213112170 {
1213212171 // Small leftover, but not dust
12133- let res = need_to_add_funding_change_output(false, 128_100, &prevouts , &outputs, funding_feerate_sat_per_1000_weight, 100);
12134- assert_eq!(res.unwrap().unwrap() , 154);
12172+ let res = need_to_add_funding_change_output(false, 128_100, &input_prevouts , &outputs, funding_feerate_sat_per_1000_weight, 100);
12173+ assert_eq!(res.unwrap(), 154);
1213512174 }
1213612175 }
1213712176}
0 commit comments