@@ -5977,13 +5977,8 @@ pub(super) struct FundingNegotiationContext {
59775977 /// The input spending the previous funding output, if this is a splice.
59785978 #[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
59795979 pub shared_funding_input: Option<SharedOwnedInput>,
5980- /// The funding inputs we will be contributing to the channel.
5981- #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5982- pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
5983- /// The change output script. This will be used if needed or -- if not set -- generated using
5984- /// `SignerProvider::get_destination_script`.
5985- #[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
5986- pub change_script: Option<ScriptBuf>,
5980+ /// The components of the funding transaction that we will contribute.
5981+ pub funding_tx_contributions: FundingTxContributions,
59875982}
59885983
59895984impl FundingNegotiationContext {
@@ -6019,35 +6014,43 @@ impl FundingNegotiationContext {
60196014 script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
60206015 };
60216016
6022- // Optionally add change output
6023- if self.our_funding_contribution > SignedAmount::ZERO {
6024- let change_value_opt = calculate_change_output_value(
6017+ let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6018+ calculate_change_output_value(
60256019 &self,
60266020 self.shared_funding_input.is_some(),
60276021 &shared_funding_output.script_pubkey,
60286022 &funding_outputs,
60296023 context.holder_dust_limit_satoshis,
6030- )?;
6031- if let Some(change_value) = change_value_opt {
6032- let change_script = if let Some(script) = self.change_script {
6033- script
6034- } else {
6035- signer_provider
6036- .get_destination_script(context.channel_keys_id)
6037- .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6038- };
6039- let mut change_output =
6040- TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
6041- let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
6042- let change_output_fee =
6043- fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
6044- let change_value_decreased_with_fee =
6045- change_value.saturating_sub(change_output_fee);
6046- // Check dust limit again
6047- if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6048- change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6049- funding_outputs.push(change_output);
6050- }
6024+ )?
6025+ } else {
6026+ None
6027+ };
6028+
6029+ let (inputs_to_contribute, change_script) = match self.funding_tx_contributions {
6030+ FundingTxContributions::InputsOnly { inputs, change_script } => (inputs, change_script),
6031+ };
6032+
6033+ // Add change output if necessary
6034+ if let Some(change_value) = change_value_opt {
6035+ let change_script = if let Some(script) = change_script {
6036+ script
6037+ } else {
6038+ signer_provider
6039+ .get_destination_script(context.channel_keys_id)
6040+ .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6041+ };
6042+
6043+ let mut change_output =
6044+ TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
6045+ let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
6046+ let change_output_fee =
6047+ fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
6048+ let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
6049+
6050+ // Check dust limit again
6051+ if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6052+ change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6053+ funding_outputs.push(change_output);
60516054 }
60526055 }
60536056
@@ -6059,7 +6062,7 @@ impl FundingNegotiationContext {
60596062 feerate_sat_per_kw: self.funding_feerate_sat_per_1000_weight,
60606063 is_initiator: self.is_initiator,
60616064 funding_tx_locktime: self.funding_tx_locktime,
6062- inputs_to_contribute: self.our_funding_inputs ,
6065+ inputs_to_contribute,
60636066 shared_funding_input: self.shared_funding_input,
60646067 shared_funding_output: SharedOwnedOutput::new(
60656068 shared_funding_output,
@@ -6071,6 +6074,30 @@ impl FundingNegotiationContext {
60716074 }
60726075}
60736076
6077+ /// The components of a funding transaction that are contributed by one party.
6078+ pub enum FundingTxContributions {
6079+ /// When only inputs -- except for a possible change output -- are contributed to the funding
6080+ /// transaction. This must correspond to a positive contribution amount.
6081+ InputsOnly {
6082+ /// The inputs used to meet the contributed amount. Any excess amount will be sent to a
6083+ /// change output.
6084+ inputs: Vec<(TxIn, TransactionU16LenLimited)>,
6085+
6086+ /// An optional change output script. This will be used if needed or, if not set, generated
6087+ /// using `SignerProvider::get_destination_script`.
6088+ change_script: Option<ScriptBuf>,
6089+ },
6090+ }
6091+
6092+ impl FundingTxContributions {
6093+ /// Returns an inputs to be contributed to the funding transaction.
6094+ pub fn inputs(&self) -> &[(TxIn, TransactionU16LenLimited)] {
6095+ match self {
6096+ FundingTxContributions::InputsOnly { inputs, .. } => &inputs[..],
6097+ }
6098+ }
6099+ }
6100+
60746101// Holder designates channel data owned for the benefit of the user client.
60756102// Counterparty designates channel data owned by the another channel participant entity.
60766103pub(super) struct FundedChannel<SP: Deref>
@@ -10684,15 +10711,17 @@ where
1068410711 funding_inputs.push((tx_in, tx16));
1068510712 }
1068610713
10714+ let funding_tx_contributions =
10715+ FundingTxContributions::InputsOnly { inputs: funding_inputs, change_script };
10716+
1068710717 let prev_funding_input = self.funding.to_splice_funding_input();
1068810718 let funding_negotiation_context = FundingNegotiationContext {
1068910719 is_initiator: true,
1069010720 our_funding_contribution,
1069110721 funding_tx_locktime: LockTime::from_consensus(locktime),
1069210722 funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
1069310723 shared_funding_input: Some(prev_funding_input),
10694- our_funding_inputs: funding_inputs,
10695- change_script,
10724+ funding_tx_contributions,
1069610725 };
1069710726
1069810727 self.pending_splice = Some(PendingSplice {
@@ -10806,15 +10835,17 @@ where
1080610835 self.funding.get_value_satoshis(),
1080710836 );
1080810837
10838+ let funding_tx_contributions =
10839+ FundingTxContributions::InputsOnly { inputs: vec![], change_script: None };
10840+
1080910841 let prev_funding_input = self.funding.to_splice_funding_input();
1081010842 let funding_negotiation_context = FundingNegotiationContext {
1081110843 is_initiator: false,
1081210844 our_funding_contribution,
1081310845 funding_tx_locktime: LockTime::from_consensus(msg.locktime),
1081410846 funding_feerate_sat_per_1000_weight: msg.funding_feerate_per_kw,
1081510847 shared_funding_input: Some(prev_funding_input),
10816- our_funding_inputs: Vec::new(),
10817- change_script: None,
10848+ funding_tx_contributions,
1081810849 };
1081910850
1082010851 let mut interactive_tx_constructor = funding_negotiation_context
@@ -12505,14 +12536,17 @@ where
1250512536 unfunded_channel_age_ticks: 0,
1250612537 holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
1250712538 };
12539+ let funding_tx_contributions = FundingTxContributions::InputsOnly {
12540+ inputs: funding_inputs,
12541+ change_script: None,
12542+ };
1250812543 let funding_negotiation_context = FundingNegotiationContext {
1250912544 is_initiator: true,
1251012545 our_funding_contribution: SignedAmount::from_sat(funding_satoshis as i64),
1251112546 funding_tx_locktime,
1251212547 funding_feerate_sat_per_1000_weight,
1251312548 shared_funding_input: None,
12514- our_funding_inputs: funding_inputs,
12515- change_script: None,
12549+ funding_tx_contributions,
1251612550 };
1251712551 let chan = Self {
1251812552 funding,
@@ -12659,14 +12693,17 @@ where
1265912693 &funding.get_counterparty_pubkeys().revocation_basepoint);
1266012694 context.channel_id = channel_id;
1266112695
12696+ let funding_tx_contributions = FundingTxContributions::InputsOnly {
12697+ inputs: our_funding_inputs.clone(),
12698+ change_script: None,
12699+ };
1266212700 let funding_negotiation_context = FundingNegotiationContext {
1266312701 is_initiator: false,
1266412702 our_funding_contribution,
1266512703 funding_tx_locktime: LockTime::from_consensus(msg.locktime),
1266612704 funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
1266712705 shared_funding_input: None,
12668- our_funding_inputs: our_funding_inputs.clone(),
12669- change_script: None,
12706+ funding_tx_contributions,
1267012707 };
1267112708 let shared_funding_output = TxOut {
1267212709 value: Amount::from_sat(funding.get_value_satoshis()),
0 commit comments