@@ -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.
@@ -2780,86 +2778,6 @@ impl<SP: Deref> PendingV2Channel<SP>
27802778where
27812779 SP::Target: SignerProvider,
27822780{
2783- /// Prepare and start interactive transaction negotiation.
2784- /// `change_destination_opt` - Optional destination for optional change; if None,
2785- /// default destination address is used.
2786- /// If error occurs, it is caused by our side, not the counterparty.
2787- #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled
2788- #[rustfmt::skip]
2789- fn begin_interactive_funding_tx_construction<ES: Deref>(
2790- &mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey,
2791- change_destination_opt: Option<ScriptBuf>,
2792- ) -> Result<Option<InteractiveTxMessageSend>, AbortReason>
2793- where ES::Target: EntropySource
2794- {
2795- debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_)));
2796- debug_assert!(self.interactive_tx_constructor.is_none());
2797-
2798- let mut funding_inputs = Vec::new();
2799- mem::swap(&mut self.funding_negotiation_context.our_funding_inputs, &mut funding_inputs);
2800-
2801- // TODO(splicing): Add prev funding tx as input, must be provided as a parameter
2802-
2803- // Add output for funding tx
2804- // Note: For the error case when the inputs are insufficient, it will be handled after
2805- // the `calculate_change_output_value` call below
2806- let mut funding_outputs = Vec::new();
2807-
2808- let shared_funding_output = TxOut {
2809- value: Amount::from_sat(self.funding.get_value_satoshis()),
2810- script_pubkey: self.funding.get_funding_redeemscript().to_p2wsh(),
2811- };
2812-
2813- // Optionally add change output
2814- let change_script = if let Some(script) = change_destination_opt {
2815- script
2816- } else {
2817- signer_provider.get_destination_script(self.context.channel_keys_id)
2818- .map_err(|_err| AbortReason::InternalError("Error getting destination script"))?
2819- };
2820- let change_value_opt = calculate_change_output_value(
2821- self.funding.is_outbound(), self.funding_negotiation_context.our_funding_satoshis,
2822- &funding_inputs, None,
2823- &shared_funding_output.script_pubkey, &funding_outputs,
2824- self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
2825- change_script.minimal_non_dust().to_sat(),
2826- )?;
2827- if let Some(change_value) = change_value_opt {
2828- let mut change_output = TxOut {
2829- value: Amount::from_sat(change_value),
2830- script_pubkey: change_script,
2831- };
2832- let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
2833- let change_output_fee = fee_for_weight(self.funding_negotiation_context.funding_feerate_sat_per_1000_weight, change_output_weight);
2834- let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
2835- // Check dust limit again
2836- if change_value_decreased_with_fee > self.context.holder_dust_limit_satoshis {
2837- change_output.value = Amount::from_sat(change_value_decreased_with_fee);
2838- funding_outputs.push(change_output);
2839- }
2840- }
2841-
2842- let constructor_args = InteractiveTxConstructorArgs {
2843- entropy_source,
2844- holder_node_id,
2845- counterparty_node_id: self.context.counterparty_node_id,
2846- channel_id: self.context.channel_id(),
2847- feerate_sat_per_kw: self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
2848- is_initiator: self.funding.is_outbound(),
2849- funding_tx_locktime: self.funding_negotiation_context.funding_tx_locktime,
2850- inputs_to_contribute: funding_inputs,
2851- shared_funding_input: None,
2852- shared_funding_output: SharedOwnedOutput::new(shared_funding_output, self.funding_negotiation_context.our_funding_satoshis),
2853- outputs_to_contribute: funding_outputs,
2854- };
2855- let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
2856- let msg = tx_constructor.take_initiator_first_message();
2857-
2858- self.interactive_tx_constructor = Some(tx_constructor);
2859-
2860- Ok(msg)
2861- }
2862-
28632781 pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
28642782 InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
28652783 Some(ref mut tx_constructor) => tx_constructor
@@ -2939,7 +2857,7 @@ where
29392857 where
29402858 L::Target: Logger
29412859 {
2942- let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis ;
2860+ let our_funding_satoshis = self.funding_negotiation_context.our_funding_contribution_satoshis ;
29432861 let transaction_number = self.unfunded_context.transaction_number();
29442862
29452863 let mut output_index = None;
@@ -5862,28 +5780,107 @@ fn check_v2_funding_inputs_sufficient(
58625780
58635781/// Context for negotiating channels (dual-funded V2 open, splicing)
58645782pub(super) struct FundingNegotiationContext {
5783+ /// Whether we initiated the funding negotiation.
5784+ pub is_initiator: bool,
58655785 /// The amount in satoshis we will be contributing to the channel.
5866- pub our_funding_satoshis: u64 ,
5786+ pub our_funding_contribution_satoshis: i64 ,
58675787 /// The amount in satoshis our counterparty will be contributing to the channel.
58685788 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5869- pub their_funding_satoshis : Option<u64 >,
5789+ pub their_funding_contribution_satoshis : Option<i64 >,
58705790 /// The funding transaction locktime suggested by the initiator. If set by us, it is always set
58715791 /// to the current block height to align incentives against fee-sniping.
58725792 pub funding_tx_locktime: LockTime,
58735793 /// The feerate set by the initiator to be used for the funding transaction.
58745794 #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled.
58755795 pub funding_feerate_sat_per_1000_weight: u32,
58765796 /// The funding inputs we will be contributing to the channel.
5877- ///
5878- /// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs`
5879- /// minus any fees paid for our contributed weight. This means that change will never be generated
5880- /// and the maximum value possible will go towards funding the channel.
5881- ///
5882- /// Note that this field may be emptied once the interactive negotiation has been started.
58835797 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
58845798 pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
58855799}
58865800
5801+ impl FundingNegotiationContext {
5802+ /// Prepare and start interactive transaction negotiation.
5803+ /// `change_destination_opt` - Optional destination for optional change; if None,
5804+ /// default destination address is used.
5805+ /// If error occurs, it is caused by our side, not the counterparty.
5806+ #[cfg(splicing)]
5807+ fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
5808+ self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
5809+ entropy_source: &ES, holder_node_id: PublicKey, change_destination_opt: Option<ScriptBuf>,
5810+ shared_funding_input: Option<SharedOwnedInput>,
5811+ ) -> Result<InteractiveTxConstructor, AbortReason>
5812+ where
5813+ SP::Target: SignerProvider,
5814+ ES::Target: EntropySource,
5815+ {
5816+ if shared_funding_input.is_some() {
5817+ debug_assert!(matches!(context.channel_state, ChannelState::ChannelReady(_)));
5818+ } else {
5819+ debug_assert!(matches!(context.channel_state, ChannelState::NegotiatingFunding(_)));
5820+ }
5821+
5822+ // Add output for funding tx
5823+ // Note: For the error case when the inputs are insufficient, it will be handled after
5824+ // the `calculate_change_output_value` call below
5825+ let mut funding_outputs = Vec::new();
5826+
5827+ let shared_funding_output = TxOut {
5828+ value: Amount::from_sat(funding.get_value_satoshis()),
5829+ script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
5830+ };
5831+
5832+ // Optionally add change output
5833+ if self.our_funding_contribution_satoshis > 0 {
5834+ let change_script = if let Some(script) = change_destination_opt {
5835+ script
5836+ } else {
5837+ signer_provider.get_destination_script(context.channel_keys_id).map_err(|_err| {
5838+ AbortReason::InternalError("Error getting destination script")
5839+ })?
5840+ };
5841+ let change_value_opt = calculate_change_output_value(
5842+ &self,
5843+ funding.channel_transaction_parameters.splice_parent_funding_txid.is_some(),
5844+ &shared_funding_output.script_pubkey,
5845+ &funding_outputs,
5846+ change_script.minimal_non_dust().to_sat(),
5847+ )?;
5848+ if let Some(change_value) = change_value_opt {
5849+ let mut change_output =
5850+ TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
5851+ let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
5852+ let change_output_fee =
5853+ fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
5854+ let change_value_decreased_with_fee =
5855+ change_value.saturating_sub(change_output_fee);
5856+ // Check dust limit again
5857+ if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
5858+ change_output.value = Amount::from_sat(change_value_decreased_with_fee);
5859+ funding_outputs.push(change_output);
5860+ }
5861+ }
5862+ }
5863+
5864+ let constructor_args = InteractiveTxConstructorArgs {
5865+ entropy_source,
5866+ holder_node_id,
5867+ counterparty_node_id: context.counterparty_node_id,
5868+ channel_id: context.channel_id(),
5869+ feerate_sat_per_kw: self.funding_feerate_sat_per_1000_weight,
5870+ is_initiator: self.is_initiator,
5871+ funding_tx_locktime: self.funding_tx_locktime,
5872+ inputs_to_contribute: self.our_funding_inputs,
5873+ shared_funding_input,
5874+ shared_funding_output: SharedOwnedOutput::new(
5875+ shared_funding_output,
5876+ funding.value_to_self_msat / 1000,
5877+ ),
5878+ outputs_to_contribute: funding_outputs,
5879+ };
5880+ InteractiveTxConstructor::new(constructor_args)
5881+ }
5882+ }
5883+
58875884// Holder designates channel data owned for the benefit of the user client.
58885885// Counterparty designates channel data owned by the another channel participant entity.
58895886pub(super) struct FundedChannel<SP: Deref>
@@ -10194,11 +10191,13 @@ where
1019410191 ) -> Result<msgs::SpliceInit, APIError> {
1019510192 // Check if a splice has been initiated already.
1019610193 // Note: only a single outstanding splice is supported (per spec)
10197- if let Some(splice_info) = &self.pending_splice {
10198- return Err(APIError::APIMisuseError { err: format!(
10199- "Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
10200- self.context.channel_id(), splice_info.our_funding_contribution
10201- )});
10194+ if self.pending_splice.is_some() {
10195+ return Err(APIError::APIMisuseError {
10196+ err: format!(
10197+ "Channel {} cannot be spliced, as it has already a splice pending",
10198+ self.context.channel_id(),
10199+ ),
10200+ });
1020210201 }
1020310202
1020410203 if !self.context.is_live() {
@@ -10231,7 +10230,6 @@ where
1023110230 )})?;
1023210231
1023310232 self.pending_splice = Some(PendingSplice {
10234- our_funding_contribution: our_funding_contribution_satoshis,
1023510233 funding_negotiation: None,
1023610234 sent_funding_txid: None,
1023710235 received_funding_txid: None,
@@ -10268,9 +10266,10 @@ where
1026810266 let our_funding_contribution_satoshis = 0i64;
1026910267
1027010268 // Check if a splice has been initiated already.
10271- if let Some(splice_info) = & self.pending_splice {
10269+ if self.pending_splice.is_some() {
1027210270 return Err(ChannelError::Warn(format!(
10273- "Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
10271+ "Channel {} already has a splice pending",
10272+ self.context.channel_id(),
1027410273 )));
1027510274 }
1027610275
@@ -11880,9 +11879,10 @@ where
1188011879 holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
1188111880 };
1188211881 let funding_negotiation_context = FundingNegotiationContext {
11883- our_funding_satoshis: funding_satoshis,
11882+ is_initiator: true,
11883+ our_funding_contribution_satoshis: funding_satoshis as i64,
1188411884 // TODO(dual_funding) TODO(splicing) Include counterparty contribution, once that's enabled
11885- their_funding_satoshis : None,
11885+ their_funding_contribution_satoshis : None,
1188611886 funding_tx_locktime,
1188711887 funding_feerate_sat_per_1000_weight,
1188811888 our_funding_inputs: funding_inputs,
@@ -12040,8 +12040,9 @@ where
1204012040 context.channel_id = channel_id;
1204112041
1204212042 let funding_negotiation_context = FundingNegotiationContext {
12043- our_funding_satoshis: our_funding_satoshis,
12044- their_funding_satoshis: Some(msg.common_fields.funding_satoshis),
12043+ is_initiator: false,
12044+ our_funding_contribution_satoshis: our_funding_satoshis as i64,
12045+ their_funding_contribution_satoshis: Some(msg.common_fields.funding_satoshis as i64),
1204512046 funding_tx_locktime: LockTime::from_consensus(msg.locktime),
1204612047 funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
1204712048 our_funding_inputs: our_funding_inputs.clone(),
@@ -12143,7 +12144,8 @@ where
1214312144 }),
1214412145 channel_type: Some(self.funding.get_channel_type().clone()),
1214512146 },
12146- funding_satoshis: self.funding_negotiation_context.our_funding_satoshis,
12147+ funding_satoshis: self.funding_negotiation_context.our_funding_contribution_satoshis
12148+ as u64,
1214712149 second_per_commitment_point,
1214812150 require_confirmed_inputs: None,
1214912151 }
0 commit comments