@@ -1665,14 +1665,19 @@ impl InteractiveTxConstructor {
16651665/// Determine whether a change output should be added or not, and if so, of what size,
16661666/// considering our given inputs, outputs, and intended contribution.
16671667/// Computes and takes into account fees.
1668- /// Return value is the value computed for the change output (in satoshis),
1669- /// or None if a change is not needed/possible.
1668+ /// Three outcomes are possible:
1669+ /// - Inputs are sufficient for intended contribution, fees, and a larger-than-dust change:
1670+ /// Ok(Some(change_amount))
1671+ /// - Inputs are sufficient for intended contribution and fees, but not for a change:
1672+ /// Ok(None)
1673+ /// - Insputs are not sufficent to cover contribution and fees:
1674+ /// Err(AbortReason::InsufficientFees)
16701675#[ allow( dead_code) ] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
16711676pub ( super ) fn calculate_change_output_value (
16721677 is_initiator : bool , our_contribution : u64 , funding_inputs_prev_outputs : & Vec < & TxOut > ,
16731678 funding_outputs : & Vec < OutputOwned > , funding_feerate_sat_per_1000_weight : u32 ,
16741679 holder_dust_limit_satoshis : u64 ,
1675- ) -> Option < u64 > {
1680+ ) -> Result < Option < u64 > , AbortReason > {
16761681 let our_funding_inputs_weight =
16771682 funding_inputs_prev_outputs. iter ( ) . fold ( 0u64 , |weight, prev_output| {
16781683 weight. saturating_add ( estimate_input_weight ( prev_output) . to_wu ( ) )
@@ -1695,13 +1700,19 @@ pub(super) fn calculate_change_output_value(
16951700 funding_inputs_prev_outputs. iter ( ) . map ( |out| out. value . to_sat ( ) ) . sum ( ) ;
16961701
16971702 // Note: in case of additional outputs, they will have to be subtracted here
1698- let remaining_value =
1699- total_input_satoshis. saturating_sub ( our_contribution) . saturating_sub ( fees_sats) ;
17001703
1701- if remaining_value <= holder_dust_limit_satoshis {
1702- None
1704+ let min_contribution_and_fees = our_contribution. saturating_add ( fees_sats) ;
1705+ let min_contribution_and_fees_and_dust = min_contribution_and_fees. saturating_add ( holder_dust_limit_satoshis) ;
1706+ if total_input_satoshis < min_contribution_and_fees {
1707+ // Not enough to cover contribution plus fees
1708+ Err ( AbortReason :: InsufficientFees )
1709+ } else if total_input_satoshis < min_contribution_and_fees_and_dust {
1710+ // Enough to cover contribution plus fees, but leftover is below dust limit
1711+ Ok ( None )
17031712 } else {
1704- Some ( remaining_value)
1713+ // Enough to have over-dust change
1714+ let remaining_value = total_input_satoshis. saturating_sub ( min_contribution_and_fees) ;
1715+ Ok ( Some ( remaining_value) )
17051716 }
17061717}
17071718
@@ -2665,7 +2676,7 @@ mod tests {
26652676 funding_feerate_sat_per_1000_weight,
26662677 300 ,
26672678 ) ;
2668- assert_eq ! ( res. unwrap( ) , gross_change - fees - common_fees) ;
2679+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , gross_change - fees - common_fees) ;
26692680 }
26702681 {
26712682 // There is leftover for change, without common fees
@@ -2677,7 +2688,7 @@ mod tests {
26772688 funding_feerate_sat_per_1000_weight,
26782689 300 ,
26792690 ) ;
2680- assert_eq ! ( res. unwrap( ) , gross_change - fees) ;
2691+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , gross_change - fees) ;
26812692 }
26822693 {
26832694 // Larger fee, smaller change
@@ -2689,7 +2700,7 @@ mod tests {
26892700 9000 ,
26902701 300 ,
26912702 ) ;
2692- assert_eq ! ( res. unwrap( ) , 14384 ) ;
2703+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , 14384 ) ;
26932704 }
26942705 {
26952706 // Insufficient inputs, no leftover
@@ -2701,7 +2712,7 @@ mod tests {
27012712 funding_feerate_sat_per_1000_weight,
27022713 300 ,
27032714 ) ;
2704- assert ! ( res. is_none ( ) ) ;
2715+ assert_eq ! ( res. err ( ) . unwrap ( ) , AbortReason :: InsufficientFees ) ;
27052716 }
27062717 {
27072718 // Very small leftover
@@ -2713,7 +2724,7 @@ mod tests {
27132724 funding_feerate_sat_per_1000_weight,
27142725 300 ,
27152726 ) ;
2716- assert ! ( res. is_none( ) ) ;
2727+ assert ! ( res. unwrap ( ) . is_none( ) ) ;
27172728 }
27182729 {
27192730 // Small leftover, but not dust
@@ -2725,7 +2736,7 @@ mod tests {
27252736 funding_feerate_sat_per_1000_weight,
27262737 100 ,
27272738 ) ;
2728- assert_eq ! ( res. unwrap( ) , 154 ) ;
2739+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , 154 ) ;
27292740 }
27302741 }
27312742}
0 commit comments