@@ -1667,14 +1667,19 @@ impl InteractiveTxConstructor {
1667
1667
/// Determine whether a change output should be added or not, and if so, of what size,
1668
1668
/// considering our given inputs, outputs, and intended contribution.
1669
1669
/// 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)
1672
1677
#[ allow( dead_code) ] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
1673
1678
pub ( super ) fn calculate_change_output_value (
1674
1679
is_initiator : bool , our_contribution : u64 , funding_inputs_prev_outputs : & Vec < & TxOut > ,
1675
1680
funding_outputs : & Vec < OutputOwned > , funding_feerate_sat_per_1000_weight : u32 ,
1676
1681
holder_dust_limit_satoshis : u64 ,
1677
- ) -> Option < u64 > {
1682
+ ) -> Result < Option < u64 > , AbortReason > {
1678
1683
let our_funding_inputs_weight =
1679
1684
funding_inputs_prev_outputs. iter ( ) . fold ( 0u64 , |weight, prev_output| {
1680
1685
weight. saturating_add ( estimate_input_weight ( prev_output) . to_wu ( ) )
@@ -1697,13 +1702,19 @@ pub(super) fn calculate_change_output_value(
1697
1702
funding_inputs_prev_outputs. iter ( ) . map ( |out| out. value . to_sat ( ) ) . sum ( ) ;
1698
1703
1699
1704
// 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) ;
1702
1705
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 )
1705
1714
} 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) )
1707
1718
}
1708
1719
}
1709
1720
@@ -2667,7 +2678,7 @@ mod tests {
2667
2678
funding_feerate_sat_per_1000_weight,
2668
2679
300 ,
2669
2680
) ;
2670
- assert_eq ! ( res. unwrap( ) , gross_change - fees - common_fees) ;
2681
+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , gross_change - fees - common_fees) ;
2671
2682
}
2672
2683
{
2673
2684
// There is leftover for change, without common fees
@@ -2679,7 +2690,7 @@ mod tests {
2679
2690
funding_feerate_sat_per_1000_weight,
2680
2691
300 ,
2681
2692
) ;
2682
- assert_eq ! ( res. unwrap( ) , gross_change - fees) ;
2693
+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , gross_change - fees) ;
2683
2694
}
2684
2695
{
2685
2696
// Larger fee, smaller change
@@ -2691,7 +2702,7 @@ mod tests {
2691
2702
9000 ,
2692
2703
300 ,
2693
2704
) ;
2694
- assert_eq ! ( res. unwrap( ) , 14384 ) ;
2705
+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , 14384 ) ;
2695
2706
}
2696
2707
{
2697
2708
// Insufficient inputs, no leftover
@@ -2703,7 +2714,7 @@ mod tests {
2703
2714
funding_feerate_sat_per_1000_weight,
2704
2715
300 ,
2705
2716
) ;
2706
- assert ! ( res. is_none ( ) ) ;
2717
+ assert_eq ! ( res. err ( ) . unwrap ( ) , AbortReason :: InsufficientFees ) ;
2707
2718
}
2708
2719
{
2709
2720
// Very small leftover
@@ -2715,7 +2726,7 @@ mod tests {
2715
2726
funding_feerate_sat_per_1000_weight,
2716
2727
300 ,
2717
2728
) ;
2718
- assert ! ( res. is_none( ) ) ;
2729
+ assert ! ( res. unwrap ( ) . is_none( ) ) ;
2719
2730
}
2720
2731
{
2721
2732
// Small leftover, but not dust
@@ -2727,7 +2738,7 @@ mod tests {
2727
2738
funding_feerate_sat_per_1000_weight,
2728
2739
100 ,
2729
2740
) ;
2730
- assert_eq ! ( res. unwrap( ) , 154 ) ;
2741
+ assert_eq ! ( res. unwrap( ) . unwrap ( ) , 154 ) ;
2731
2742
}
2732
2743
}
2733
2744
}
0 commit comments