@@ -22,7 +22,7 @@ use bitcoin::{OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Wei
2222use crate :: chain:: chaininterface:: fee_for_weight;
2323use crate :: events:: bump_transaction:: { BASE_INPUT_WEIGHT , EMPTY_SCRIPT_SIG_WEIGHT } ;
2424use crate :: ln:: chan_utils:: FUNDING_TRANSACTION_WITNESS_WEIGHT ;
25- use crate :: ln:: channel:: TOTAL_BITCOIN_SUPPLY_SATOSHIS ;
25+ use crate :: ln:: channel:: { FundingNegotiationContext , TOTAL_BITCOIN_SUPPLY_SATOSHIS } ;
2626use crate :: ln:: msgs;
2727use crate :: ln:: msgs:: { MessageSendEvent , SerialId , TxSignatures } ;
2828use crate :: ln:: types:: ChannelId ;
@@ -1874,26 +1874,21 @@ impl InteractiveTxConstructor {
18741874/// `Err(AbortReason::InsufficientFees)`
18751875///
18761876/// Parameters:
1877- /// - `is_initiator` - Whether we are the negotiation initiator or not (acceptor).
1878- /// - `our_contribution` - The sats amount we intend to contribute to the funding
1879- /// transaction being negotiated.
1880- /// - `funding_inputs` - List of our inputs. It does not include the shared input, if there is one.
1877+ /// - `context` - Context of the funding negotiation, including non-shared inputs and feerate.
18811878/// - `shared_input` - The locally owned amount of the shared input (in sats), if there is one.
18821879/// - `shared_output_funding_script` - The script of the shared output.
18831880/// - `funding_outputs` - Our funding outputs.
1884- /// - `funding_feerate_sat_per_1000_weight` - Fee rate to be used.
18851881/// - `change_output_dust_limit` - The dust limit (in sats) to consider.
18861882pub ( super ) fn calculate_change_output_value (
1887- is_initiator : bool , our_contribution : u64 ,
1888- funding_inputs : & Vec < ( TxIn , TransactionU16LenLimited ) > , shared_input : Option < u64 > ,
1883+ context : & FundingNegotiationContext , shared_input : Option < u64 > ,
18891884 shared_output_funding_script : & ScriptBuf , funding_outputs : & Vec < TxOut > ,
1890- funding_feerate_sat_per_1000_weight : u32 , change_output_dust_limit : u64 ,
1885+ change_output_dust_limit : u64 ,
18911886) -> Result < Option < u64 > , AbortReason > {
18921887 // Process inputs and their prev txs:
18931888 // calculate value sum and weight sum of inputs, also perform checks
18941889 let mut total_input_satoshis = 0u64 ;
18951890 let mut our_funding_inputs_weight = 0u64 ;
1896- for ( txin, tx) in funding_inputs . iter ( ) {
1891+ for ( txin, tx) in context . our_funding_inputs . iter ( ) {
18971892 let txid = tx. as_transaction ( ) . compute_txid ( ) ;
18981893 if txin. previous_output . txid != txid {
18991894 return Err ( AbortReason :: PrevTxOutInvalid ) ;
@@ -1922,7 +1917,7 @@ pub(super) fn calculate_change_output_value(
19221917
19231918 // If we are the initiator, we must pay for the weight of the funding output and
19241919 // all common fields in the funding transaction.
1925- if is_initiator {
1920+ if context . is_initiator {
19261921 weight = weight. saturating_add ( get_output_weight ( shared_output_funding_script) . to_wu ( ) ) ;
19271922 weight = weight. saturating_add ( TX_COMMON_FIELDS_WEIGHT ) ;
19281923
@@ -1931,15 +1926,15 @@ pub(super) fn calculate_change_output_value(
19311926 }
19321927 }
19331928
1934- let fees_sats = fee_for_weight ( funding_feerate_sat_per_1000_weight, weight) ;
1929+ let fees_sats = fee_for_weight ( context . funding_feerate_sat_per_1000_weight , weight) ;
19351930
19361931 let net_total_less_fees =
19371932 total_input_satoshis. saturating_sub ( total_output_satoshis) . saturating_sub ( fees_sats) ;
1938- if net_total_less_fees < our_contribution {
1933+ if net_total_less_fees < context . our_funding_satoshis {
19391934 // Not enough to cover contribution plus fees
19401935 return Err ( AbortReason :: InsufficientFees ) ;
19411936 }
1942- let remaining_value = net_total_less_fees. saturating_sub ( our_contribution ) ;
1937+ let remaining_value = net_total_less_fees. saturating_sub ( context . our_funding_satoshis ) ;
19431938 if remaining_value < change_output_dust_limit {
19441939 // Enough to cover contribution plus fees, but leftover is below dust limit; no change
19451940 Ok ( None )
@@ -1952,7 +1947,7 @@ pub(super) fn calculate_change_output_value(
19521947#[ cfg( test) ]
19531948mod tests {
19541949 use crate :: chain:: chaininterface:: { fee_for_weight, FEERATE_FLOOR_SATS_PER_KW } ;
1955- use crate :: ln:: channel:: TOTAL_BITCOIN_SUPPLY_SATOSHIS ;
1950+ use crate :: ln:: channel:: { FundingNegotiationContext , TOTAL_BITCOIN_SUPPLY_SATOSHIS } ;
19561951 use crate :: ln:: interactivetxs:: {
19571952 calculate_change_output_value, generate_holder_serial_id, AbortReason ,
19581953 HandleTxCompleteValue , InteractiveTxConstructor , InteractiveTxConstructorArgs ,
@@ -2980,89 +2975,74 @@ mod tests {
29802975 let gross_change = total_inputs - total_outputs - our_contributed;
29812976 let fees = 1746 ;
29822977 let common_fees = 234 ;
2983- {
2984- // There is leftover for change
2985- let res = calculate_change_output_value (
2986- true ,
2987- our_contributed,
2988- & inputs,
2989- None ,
2990- & ScriptBuf :: new ( ) ,
2991- & outputs,
2992- funding_feerate_sat_per_1000_weight,
2993- 300 ,
2994- ) ;
2995- assert_eq ! ( res, Ok ( Some ( gross_change - fees - common_fees) ) ) ;
2996- }
2997- {
2998- // There is leftover for change, without common fees
2999- let res = calculate_change_output_value (
3000- false ,
3001- our_contributed,
3002- & inputs,
3003- None ,
3004- & ScriptBuf :: new ( ) ,
3005- & outputs,
3006- funding_feerate_sat_per_1000_weight,
3007- 300 ,
3008- ) ;
3009- assert_eq ! ( res, Ok ( Some ( gross_change - fees) ) ) ;
3010- }
3011- {
3012- // Larger fee, smaller change
3013- let res = calculate_change_output_value (
3014- true ,
3015- our_contributed,
3016- & inputs,
3017- None ,
3018- & ScriptBuf :: new ( ) ,
3019- & outputs,
3020- funding_feerate_sat_per_1000_weight * 3 ,
3021- 300 ,
3022- ) ;
3023- assert_eq ! ( res, Ok ( Some ( 4060 ) ) ) ;
3024- }
3025- {
3026- // Insufficient inputs, no leftover
3027- let res = calculate_change_output_value (
3028- false ,
3029- 130_000 ,
3030- & inputs,
3031- None ,
3032- & ScriptBuf :: new ( ) ,
3033- & outputs,
3034- funding_feerate_sat_per_1000_weight,
3035- 300 ,
3036- ) ;
3037- assert_eq ! ( res, Err ( AbortReason :: InsufficientFees ) ) ;
3038- }
3039- {
3040- // Very small leftover
3041- let res = calculate_change_output_value (
3042- false ,
3043- 118_000 ,
3044- & inputs,
3045- None ,
3046- & ScriptBuf :: new ( ) ,
3047- & outputs,
3048- funding_feerate_sat_per_1000_weight,
3049- 300 ,
3050- ) ;
3051- assert_eq ! ( res, Ok ( None ) ) ;
3052- }
3053- {
3054- // Small leftover, but not dust
3055- let res = calculate_change_output_value (
3056- false ,
3057- 117_992 ,
3058- & inputs,
3059- None ,
3060- & ScriptBuf :: new ( ) ,
3061- & outputs,
3062- funding_feerate_sat_per_1000_weight,
3063- 100 ,
3064- ) ;
3065- assert_eq ! ( res, Ok ( Some ( 262 ) ) ) ;
3066- }
2978+
2979+ // There is leftover for change
2980+ let context = FundingNegotiationContext {
2981+ is_initiator : true ,
2982+ our_funding_satoshis : our_contributed,
2983+ their_funding_satoshis : None ,
2984+ funding_tx_locktime : AbsoluteLockTime :: ZERO ,
2985+ funding_feerate_sat_per_1000_weight,
2986+ our_funding_inputs : inputs,
2987+ } ;
2988+ assert_eq ! (
2989+ calculate_change_output_value( & context, None , & ScriptBuf :: new( ) , & outputs, 300 ) ,
2990+ Ok ( Some ( gross_change - fees - common_fees) ) ,
2991+ ) ;
2992+
2993+ // There is leftover for change, without common fees
2994+ let context = FundingNegotiationContext {
2995+ is_initiator : false ,
2996+ ..context
2997+ } ;
2998+ assert_eq ! (
2999+ calculate_change_output_value( & context, None , & ScriptBuf :: new( ) , & outputs, 300 ) ,
3000+ Ok ( Some ( gross_change - fees) ) ,
3001+ ) ;
3002+
3003+ // Larger fee, smaller change
3004+ let context = FundingNegotiationContext {
3005+ is_initiator : true ,
3006+ funding_feerate_sat_per_1000_weight : funding_feerate_sat_per_1000_weight * 3 ,
3007+ ..context
3008+ } ;
3009+ assert_eq ! (
3010+ calculate_change_output_value( & context, None , & ScriptBuf :: new( ) , & outputs, 300 ) ,
3011+ Ok ( Some ( 4060 ) ) ,
3012+ ) ;
3013+
3014+ // Insufficient inputs, no leftover
3015+ let context = FundingNegotiationContext {
3016+ is_initiator : false ,
3017+ our_funding_satoshis : 130_000 ,
3018+ funding_feerate_sat_per_1000_weight : funding_feerate_sat_per_1000_weight,
3019+ ..context
3020+ } ;
3021+ assert_eq ! (
3022+ calculate_change_output_value( & context, None , & ScriptBuf :: new( ) , & outputs, 300 ) ,
3023+ Err ( AbortReason :: InsufficientFees ) ,
3024+ ) ;
3025+
3026+ // Very small leftover
3027+ let context = FundingNegotiationContext {
3028+ is_initiator : false ,
3029+ our_funding_satoshis : 118_000 ,
3030+ ..context
3031+ } ;
3032+ assert_eq ! (
3033+ calculate_change_output_value( & context, None , & ScriptBuf :: new( ) , & outputs, 300 ) ,
3034+ Ok ( None ) ,
3035+ ) ;
3036+
3037+ // Small leftover, but not dust
3038+ let context = FundingNegotiationContext {
3039+ is_initiator : false ,
3040+ our_funding_satoshis : 117_992 ,
3041+ ..context
3042+ } ;
3043+ assert_eq ! (
3044+ calculate_change_output_value( & context, None , & ScriptBuf :: new( ) , & outputs, 100 ) ,
3045+ Ok ( Some ( 262 ) ) ,
3046+ ) ;
30673047 }
30683048}
0 commit comments