@@ -57,9 +57,8 @@ use crate::ln::channelmanager::{
5757};
5858use crate::ln::interactivetxs::{
5959 calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteResult,
60- InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend,
61- InteractiveTxMessageSendResult, InteractiveTxSigningSession, SharedOwnedOutput,
62- TX_COMMON_FIELDS_WEIGHT,
60+ InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSendResult,
61+ InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
6362};
6463use crate::ln::msgs;
6564use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
@@ -2176,7 +2175,6 @@ impl FundingScope {
21762175/// Info about a pending splice, used in the pre-splice channel
21772176#[cfg(splicing)]
21782177struct PendingSplice {
2179- pub our_funding_contribution: i64,
21802178 funding_negotiation: Option<FundingNegotiation>,
21812179
21822180 /// The funding txid used in the `splice_locked` sent to the counterparty.
@@ -2778,86 +2776,6 @@ impl<SP: Deref> PendingV2Channel<SP>
27782776where
27792777 SP::Target: SignerProvider,
27802778{
2781- /// Prepare and start interactive transaction negotiation.
2782- /// `change_destination_opt` - Optional destination for optional change; if None,
2783- /// default destination address is used.
2784- /// If error occurs, it is caused by our side, not the counterparty.
2785- #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled
2786- #[rustfmt::skip]
2787- fn begin_interactive_funding_tx_construction<ES: Deref>(
2788- &mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey,
2789- change_destination_opt: Option<ScriptBuf>,
2790- ) -> Result<Option<InteractiveTxMessageSend>, AbortReason>
2791- where ES::Target: EntropySource
2792- {
2793- debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_)));
2794- debug_assert!(self.interactive_tx_constructor.is_none());
2795-
2796- let mut funding_inputs = Vec::new();
2797- mem::swap(&mut self.funding_negotiation_context.our_funding_inputs, &mut funding_inputs);
2798-
2799- // TODO(splicing): Add prev funding tx as input, must be provided as a parameter
2800-
2801- // Add output for funding tx
2802- // Note: For the error case when the inputs are insufficient, it will be handled after
2803- // the `calculate_change_output_value` call below
2804- let mut funding_outputs = Vec::new();
2805-
2806- let shared_funding_output = TxOut {
2807- value: Amount::from_sat(self.funding.get_value_satoshis()),
2808- script_pubkey: self.funding.get_funding_redeemscript().to_p2wsh(),
2809- };
2810-
2811- // Optionally add change output
2812- let change_script = if let Some(script) = change_destination_opt {
2813- script
2814- } else {
2815- signer_provider.get_destination_script(self.context.channel_keys_id)
2816- .map_err(|_err| AbortReason::InternalError("Error getting destination script"))?
2817- };
2818- let change_value_opt = calculate_change_output_value(
2819- self.funding.is_outbound(), self.funding_negotiation_context.our_funding_satoshis,
2820- &funding_inputs, None,
2821- &shared_funding_output.script_pubkey, &funding_outputs,
2822- self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
2823- change_script.minimal_non_dust().to_sat(),
2824- )?;
2825- if let Some(change_value) = change_value_opt {
2826- let mut change_output = TxOut {
2827- value: Amount::from_sat(change_value),
2828- script_pubkey: change_script,
2829- };
2830- let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
2831- let change_output_fee = fee_for_weight(self.funding_negotiation_context.funding_feerate_sat_per_1000_weight, change_output_weight);
2832- let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
2833- // Check dust limit again
2834- if change_value_decreased_with_fee > self.context.holder_dust_limit_satoshis {
2835- change_output.value = Amount::from_sat(change_value_decreased_with_fee);
2836- funding_outputs.push(change_output);
2837- }
2838- }
2839-
2840- let constructor_args = InteractiveTxConstructorArgs {
2841- entropy_source,
2842- holder_node_id,
2843- counterparty_node_id: self.context.counterparty_node_id,
2844- channel_id: self.context.channel_id(),
2845- feerate_sat_per_kw: self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
2846- is_initiator: self.funding.is_outbound(),
2847- funding_tx_locktime: self.funding_negotiation_context.funding_tx_locktime,
2848- inputs_to_contribute: funding_inputs,
2849- shared_funding_input: None,
2850- shared_funding_output: SharedOwnedOutput::new(shared_funding_output, self.funding_negotiation_context.our_funding_satoshis),
2851- outputs_to_contribute: funding_outputs,
2852- };
2853- let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
2854- let msg = tx_constructor.take_initiator_first_message();
2855-
2856- self.interactive_tx_constructor = Some(tx_constructor);
2857-
2858- Ok(msg)
2859- }
2860-
28612779 pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
28622780 InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
28632781 Some(ref mut tx_constructor) => tx_constructor
@@ -2937,7 +2855,7 @@ where
29372855 where
29382856 L::Target: Logger
29392857 {
2940- let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis ;
2858+ let our_funding_satoshis = self.funding_negotiation_context.our_funding_contribution_satoshis ;
29412859 let transaction_number = self.unfunded_context.transaction_number();
29422860
29432861 let mut output_index = None;
@@ -5860,28 +5778,106 @@ fn check_v2_funding_inputs_sufficient(
58605778
58615779/// Context for negotiating channels (dual-funded V2 open, splicing)
58625780pub(super) struct FundingNegotiationContext {
5781+ /// Whether we initiated the funding negotiation.
5782+ pub is_initiator: bool,
58635783 /// The amount in satoshis we will be contributing to the channel.
5864- pub our_funding_satoshis: u64 ,
5784+ pub our_funding_contribution_satoshis: i64 ,
58655785 /// The amount in satoshis our counterparty will be contributing to the channel.
58665786 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5867- pub their_funding_satoshis : Option<u64 >,
5787+ pub their_funding_contribution_satoshis : Option<i64 >,
58685788 /// The funding transaction locktime suggested by the initiator. If set by us, it is always set
58695789 /// to the current block height to align incentives against fee-sniping.
58705790 pub funding_tx_locktime: LockTime,
58715791 /// The feerate set by the initiator to be used for the funding transaction.
58725792 #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled.
58735793 pub funding_feerate_sat_per_1000_weight: u32,
58745794 /// The funding inputs we will be contributing to the channel.
5875- ///
5876- /// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs`
5877- /// minus any fees paid for our contributed weight. This means that change will never be generated
5878- /// and the maximum value possible will go towards funding the channel.
5879- ///
5880- /// Note that this field may be emptied once the interactive negotiation has been started.
58815795 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
58825796 pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
58835797}
58845798
5799+ impl FundingNegotiationContext {
5800+ /// Prepare and start interactive transaction negotiation.
5801+ /// `change_destination_opt` - Optional destination for optional change; if None,
5802+ /// default destination address is used.
5803+ /// If error occurs, it is caused by our side, not the counterparty.
5804+ fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
5805+ self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
5806+ entropy_source: &ES, holder_node_id: PublicKey, change_destination_opt: Option<ScriptBuf>,
5807+ shared_funding_input: Option<SharedOwnedInput>,
5808+ ) -> Result<InteractiveTxConstructor, AbortReason>
5809+ where
5810+ SP::Target: SignerProvider,
5811+ ES::Target: EntropySource,
5812+ {
5813+ if shared_funding_input.is_some() {
5814+ debug_assert!(matches!(context.channel_state, ChannelState::ChannelReady(_)));
5815+ } else {
5816+ debug_assert!(matches!(context.channel_state, ChannelState::NegotiatingFunding(_)));
5817+ }
5818+
5819+ // Add output for funding tx
5820+ // Note: For the error case when the inputs are insufficient, it will be handled after
5821+ // the `calculate_change_output_value` call below
5822+ let mut funding_outputs = Vec::new();
5823+
5824+ let shared_funding_output = TxOut {
5825+ value: Amount::from_sat(funding.get_value_satoshis()),
5826+ script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
5827+ };
5828+
5829+ // Optionally add change output
5830+ if self.our_funding_contribution_satoshis > 0 {
5831+ let change_script = if let Some(script) = change_destination_opt {
5832+ script
5833+ } else {
5834+ signer_provider.get_destination_script(context.channel_keys_id).map_err(|_err| {
5835+ AbortReason::InternalError("Error getting destination script")
5836+ })?
5837+ };
5838+ let change_value_opt = calculate_change_output_value(
5839+ &self,
5840+ funding.channel_transaction_parameters.splice_parent_funding_txid.is_some(),
5841+ &shared_funding_output.script_pubkey,
5842+ &funding_outputs,
5843+ change_script.minimal_non_dust().to_sat(),
5844+ )?;
5845+ if let Some(change_value) = change_value_opt {
5846+ let mut change_output =
5847+ TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
5848+ let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
5849+ let change_output_fee =
5850+ fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
5851+ let change_value_decreased_with_fee =
5852+ change_value.saturating_sub(change_output_fee);
5853+ // Check dust limit again
5854+ if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
5855+ change_output.value = Amount::from_sat(change_value_decreased_with_fee);
5856+ funding_outputs.push(change_output);
5857+ }
5858+ }
5859+ }
5860+
5861+ let constructor_args = InteractiveTxConstructorArgs {
5862+ entropy_source,
5863+ holder_node_id,
5864+ counterparty_node_id: context.counterparty_node_id,
5865+ channel_id: context.channel_id(),
5866+ feerate_sat_per_kw: self.funding_feerate_sat_per_1000_weight,
5867+ is_initiator: self.is_initiator,
5868+ funding_tx_locktime: self.funding_tx_locktime,
5869+ inputs_to_contribute: self.our_funding_inputs,
5870+ shared_funding_input,
5871+ shared_funding_output: SharedOwnedOutput::new(
5872+ shared_funding_output,
5873+ funding.value_to_self_msat / 1000,
5874+ ),
5875+ outputs_to_contribute: funding_outputs,
5876+ };
5877+ InteractiveTxConstructor::new(constructor_args)
5878+ }
5879+ }
5880+
58855881// Holder designates channel data owned for the benefit of the user client.
58865882// Counterparty designates channel data owned by the another channel participant entity.
58875883pub(super) struct FundedChannel<SP: Deref>
@@ -10192,11 +10188,13 @@ where
1019210188 ) -> Result<msgs::SpliceInit, APIError> {
1019310189 // Check if a splice has been initiated already.
1019410190 // Note: only a single outstanding splice is supported (per spec)
10195- if let Some(splice_info) = &self.pending_splice {
10196- return Err(APIError::APIMisuseError { err: format!(
10197- "Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
10198- self.context.channel_id(), splice_info.our_funding_contribution
10199- )});
10191+ if self.pending_splice.is_some() {
10192+ return Err(APIError::APIMisuseError {
10193+ err: format!(
10194+ "Channel {} cannot be spliced, as it has already a splice pending",
10195+ self.context.channel_id(),
10196+ ),
10197+ });
1020010198 }
1020110199
1020210200 if !self.context.is_live() {
@@ -10229,7 +10227,6 @@ where
1022910227 )})?;
1023010228
1023110229 self.pending_splice = Some(PendingSplice {
10232- our_funding_contribution: our_funding_contribution_satoshis,
1023310230 funding_negotiation: None,
1023410231 sent_funding_txid: None,
1023510232 received_funding_txid: None,
@@ -10266,9 +10263,10 @@ where
1026610263 let our_funding_contribution_satoshis = 0i64;
1026710264
1026810265 // Check if a splice has been initiated already.
10269- if let Some(splice_info) = & self.pending_splice {
10266+ if self.pending_splice.is_some() {
1027010267 return Err(ChannelError::Warn(format!(
10271- "Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
10268+ "Channel {} already has a splice pending",
10269+ self.context.channel_id(),
1027210270 )));
1027310271 }
1027410272
@@ -11878,9 +11876,10 @@ where
1187811876 holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
1187911877 };
1188011878 let funding_negotiation_context = FundingNegotiationContext {
11881- our_funding_satoshis: funding_satoshis,
11879+ is_initiator: true,
11880+ our_funding_contribution_satoshis: funding_satoshis as i64,
1188211881 // TODO(dual_funding) TODO(splicing) Include counterparty contribution, once that's enabled
11883- their_funding_satoshis : None,
11882+ their_funding_contribution_satoshis : None,
1188411883 funding_tx_locktime,
1188511884 funding_feerate_sat_per_1000_weight,
1188611885 our_funding_inputs: funding_inputs,
@@ -12038,8 +12037,9 @@ where
1203812037 context.channel_id = channel_id;
1203912038
1204012039 let funding_negotiation_context = FundingNegotiationContext {
12041- our_funding_satoshis: our_funding_satoshis,
12042- their_funding_satoshis: Some(msg.common_fields.funding_satoshis),
12040+ is_initiator: false,
12041+ our_funding_contribution_satoshis: our_funding_satoshis as i64,
12042+ their_funding_contribution_satoshis: Some(msg.common_fields.funding_satoshis as i64),
1204312043 funding_tx_locktime: LockTime::from_consensus(msg.locktime),
1204412044 funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
1204512045 our_funding_inputs: our_funding_inputs.clone(),
@@ -12141,7 +12141,8 @@ where
1214112141 }),
1214212142 channel_type: Some(self.funding.get_channel_type().clone()),
1214312143 },
12144- funding_satoshis: self.funding_negotiation_context.our_funding_satoshis,
12144+ funding_satoshis: self.funding_negotiation_context.our_funding_contribution_satoshis
12145+ as u64,
1214512146 second_per_commitment_point,
1214612147 require_confirmed_inputs: None,
1214712148 }
0 commit comments