@@ -1695,6 +1695,22 @@ impl InteractiveTxConstructor {
1695
1695
/// `Err(AbortReason::InsufficientFees)`
1696
1696
#[ allow( dead_code) ] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
1697
1697
pub ( super ) fn calculate_change_output_value (
1698
+ is_initiator : bool , our_contribution : u64 ,
1699
+ funding_inputs : & Vec < ( TxIn , TransactionU16LenLimited ) > , funding_outputs : & Vec < OutputOwned > ,
1700
+ funding_feerate_sat_per_1000_weight : u32 , change_output_dust_limit : u64 ,
1701
+ ) -> Result < Option < u64 > , AbortReason > {
1702
+ let funding_input_prev_outs = txouts_from_input_prev_txs ( & funding_inputs) ?;
1703
+ calculate_change_output_value_prevout (
1704
+ is_initiator,
1705
+ our_contribution,
1706
+ & funding_input_prev_outs,
1707
+ funding_outputs,
1708
+ funding_feerate_sat_per_1000_weight,
1709
+ change_output_dust_limit,
1710
+ )
1711
+ }
1712
+
1713
+ fn calculate_change_output_value_prevout (
1698
1714
is_initiator : bool , our_contribution : u64 , funding_inputs_prev_outputs : & Vec < & TxOut > ,
1699
1715
funding_outputs : & Vec < OutputOwned > , funding_feerate_sat_per_1000_weight : u32 ,
1700
1716
change_output_dust_limit : u64 ,
@@ -1734,12 +1750,34 @@ pub(super) fn calculate_change_output_value(
1734
1750
}
1735
1751
}
1736
1752
1753
+ /// Obtain prev outputs for each supplied input and matching transaction.
1754
+ /// Will error when a prev tx does not have an output for the specified vout.
1755
+ /// Also checks for matching of transaction IDs.
1756
+ fn txouts_from_input_prev_txs (
1757
+ inputs : & Vec < ( TxIn , TransactionU16LenLimited ) > ,
1758
+ ) -> Result < Vec < & TxOut > , AbortReason > {
1759
+ let mut prev_outputs: Vec < & TxOut > = Vec :: with_capacity ( inputs. len ( ) ) ;
1760
+ // Check that vouts exist for each TxIn in provided transactions.
1761
+ for ( idx, ( txin, tx) ) in inputs. iter ( ) . enumerate ( ) {
1762
+ let txid = tx. as_transaction ( ) . compute_txid ( ) ;
1763
+ if txin. previous_output . txid != txid {
1764
+ return Err ( AbortReason :: ProvidedInputsAndPrevtxsTxIdMismatch ( idx as u32 ) ) ;
1765
+ }
1766
+ if let Some ( output) = tx. as_transaction ( ) . output . get ( txin. previous_output . vout as usize ) {
1767
+ prev_outputs. push ( output) ;
1768
+ } else {
1769
+ return Err ( AbortReason :: ProvidedInputsAndPrevtxsVoutNotFound ( idx as u32 ) ) ;
1770
+ }
1771
+ }
1772
+ Ok ( prev_outputs)
1773
+ }
1774
+
1737
1775
#[ cfg( test) ]
1738
1776
mod tests {
1739
1777
use crate :: chain:: chaininterface:: { fee_for_weight, FEERATE_FLOOR_SATS_PER_KW } ;
1740
1778
use crate :: ln:: channel:: TOTAL_BITCOIN_SUPPLY_SATOSHIS ;
1741
1779
use crate :: ln:: interactivetxs:: {
1742
- calculate_change_output_value , generate_holder_serial_id, AbortReason ,
1780
+ calculate_change_output_value_prevout , generate_holder_serial_id, AbortReason ,
1743
1781
HandleTxCompleteValue , InteractiveTxConstructor , InteractiveTxConstructorArgs ,
1744
1782
InteractiveTxMessageSend , MAX_INPUTS_OUTPUTS_COUNT , MAX_RECEIVED_TX_ADD_INPUT_COUNT ,
1745
1783
MAX_RECEIVED_TX_ADD_OUTPUT_COUNT ,
@@ -2686,7 +2724,7 @@ mod tests {
2686
2724
let common_fees = 126 ;
2687
2725
{
2688
2726
// There is leftover for change
2689
- let res = calculate_change_output_value (
2727
+ let res = calculate_change_output_value_prevout (
2690
2728
true ,
2691
2729
our_contributed,
2692
2730
& input_prevouts,
@@ -2698,7 +2736,7 @@ mod tests {
2698
2736
}
2699
2737
{
2700
2738
// There is leftover for change, without common fees
2701
- let res = calculate_change_output_value (
2739
+ let res = calculate_change_output_value_prevout (
2702
2740
false ,
2703
2741
our_contributed,
2704
2742
& input_prevouts,
@@ -2710,7 +2748,7 @@ mod tests {
2710
2748
}
2711
2749
{
2712
2750
// Larger fee, smaller change
2713
- let res = calculate_change_output_value (
2751
+ let res = calculate_change_output_value_prevout (
2714
2752
true ,
2715
2753
our_contributed,
2716
2754
& input_prevouts,
@@ -2722,7 +2760,7 @@ mod tests {
2722
2760
}
2723
2761
{
2724
2762
// Insufficient inputs, no leftover
2725
- let res = calculate_change_output_value (
2763
+ let res = calculate_change_output_value_prevout (
2726
2764
false ,
2727
2765
130_000 ,
2728
2766
& input_prevouts,
@@ -2734,7 +2772,7 @@ mod tests {
2734
2772
}
2735
2773
{
2736
2774
// Very small leftover
2737
- let res = calculate_change_output_value (
2775
+ let res = calculate_change_output_value_prevout (
2738
2776
false ,
2739
2777
128_100 ,
2740
2778
& input_prevouts,
@@ -2746,7 +2784,7 @@ mod tests {
2746
2784
}
2747
2785
{
2748
2786
// Small leftover, but not dust
2749
- let res = calculate_change_output_value (
2787
+ let res = calculate_change_output_value_prevout (
2750
2788
false ,
2751
2789
128_100 ,
2752
2790
& input_prevouts,
0 commit comments