@@ -1667,14 +1667,19 @@ impl InteractiveTxConstructor {
16671667/// Determine whether a change output should be added or not, and if so, of what size,
16681668/// considering our given inputs, outputs, and intended contribution.
16691669/// Computes and takes into account fees.
1670- /// Return value is the value computed for the change output (in satoshis),
1671- /// or None if a change is not needed/possible.
1670+ /// Three outcomes are possible:
1671+ /// - Inputs are sufficient for intended contribution, fees, and a larger-than-dust change:
1672+ /// Ok(Some(change_amount))
1673+ /// - Inputs are sufficient for intended contribution and fees, but not for a change:
1674+ /// Ok(None)
1675+ /// - Insputs are not sufficent to cover contribution and fees:
1676+ /// Err(AbortReason::InsufficientFees)
16721677#[ allow( dead_code) ] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
16731678pub ( super ) fn calculate_change_output_value (
16741679 is_initiator : bool , our_contribution : u64 , funding_inputs_prev_outputs : & Vec < & TxOut > ,
16751680 funding_outputs : & Vec < OutputOwned > , funding_feerate_sat_per_1000_weight : u32 ,
16761681 holder_dust_limit_satoshis : u64 ,
1677- ) -> Option < u64 > {
1682+ ) -> Result < Option < u64 > , AbortReason > {
16781683 let our_funding_inputs_weight =
16791684 funding_inputs_prev_outputs. iter ( ) . fold ( 0u64 , |weight, prev_output| {
16801685 weight. saturating_add ( estimate_input_weight ( prev_output) . to_wu ( ) )
@@ -1697,13 +1702,19 @@ pub(super) fn calculate_change_output_value(
16971702 funding_inputs_prev_outputs. iter ( ) . map ( |out| out. value . to_sat ( ) ) . sum ( ) ;
16981703
16991704 // Note: in case of additional outputs, they will have to be subtracted here
1700- let remaining_value =
1701- total_input_satoshis. saturating_sub ( our_contribution) . saturating_sub ( fees_sats) ;
17021705
1703- if remaining_value <= holder_dust_limit_satoshis {
1704- None
1706+ let min_contribution_and_fees = our_contribution. saturating_add ( fees_sats) ;
1707+ let min_contribution_and_fees_and_dust = min_contribution_and_fees. saturating_add ( holder_dust_limit_satoshis) ;
1708+ if total_input_satoshis < min_contribution_and_fees {
1709+ // Not enough to cover contribution plus fees
1710+ Err ( AbortReason :: InsufficientFees )
1711+ } else if total_input_satoshis < min_contribution_and_fees_and_dust {
1712+ // Enough to cover contribution plus fees, but leftover is below dust limit
1713+ Ok ( None )
17051714 } else {
1706- Some ( remaining_value)
1715+ // Enough to have over-dust change
1716+ let remaining_value = total_input_satoshis. saturating_sub ( min_contribution_and_fees) ;
1717+ Ok ( Some ( remaining_value) )
17071718 }
17081719}
17091720
@@ -2667,7 +2678,7 @@ mod tests {
26672678 funding_feerate_sat_per_1000_weight,
26682679 300 ,
26692680 ) ;
2670- assert_eq ! ( res. unwrap( ) , gross_change - fees - common_fees) ;
2681+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , gross_change - fees - common_fees) ;
26712682 }
26722683 {
26732684 // There is leftover for change, without common fees
@@ -2679,7 +2690,7 @@ mod tests {
26792690 funding_feerate_sat_per_1000_weight,
26802691 300 ,
26812692 ) ;
2682- assert_eq ! ( res. unwrap( ) , gross_change - fees) ;
2693+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , gross_change - fees) ;
26832694 }
26842695 {
26852696 // Larger fee, smaller change
@@ -2691,7 +2702,7 @@ mod tests {
26912702 9000 ,
26922703 300 ,
26932704 ) ;
2694- assert_eq ! ( res. unwrap( ) , 14384 ) ;
2705+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , 14384 ) ;
26952706 }
26962707 {
26972708 // Insufficient inputs, no leftover
@@ -2703,7 +2714,7 @@ mod tests {
27032714 funding_feerate_sat_per_1000_weight,
27042715 300 ,
27052716 ) ;
2706- assert ! ( res. is_none ( ) ) ;
2717+ assert_eq ! ( res. err ( ) . unwrap ( ) , AbortReason :: InsufficientFees ) ;
27072718 }
27082719 {
27092720 // Very small leftover
@@ -2715,7 +2726,7 @@ mod tests {
27152726 funding_feerate_sat_per_1000_weight,
27162727 300 ,
27172728 ) ;
2718- assert ! ( res. is_none( ) ) ;
2729+ assert ! ( res. unwrap ( ) . is_none( ) ) ;
27192730 }
27202731 {
27212732 // Small leftover, but not dust
@@ -2727,7 +2738,7 @@ mod tests {
27272738 funding_feerate_sat_per_1000_weight,
27282739 100 ,
27292740 ) ;
2730- assert_eq ! ( res. unwrap( ) , 154 ) ;
2741+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , 154 ) ;
27312742 }
27322743 }
27332744}
0 commit comments