@@ -57,9 +57,8 @@ use crate::ln::channelmanager::{
57
57
};
58
58
use crate::ln::interactivetxs::{
59
59
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,
63
62
};
64
63
use crate::ln::msgs;
65
64
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
@@ -2171,7 +2170,6 @@ impl FundingScope {
2171
2170
/// Info about a pending splice, used in the pre-splice channel
2172
2171
#[cfg(splicing)]
2173
2172
struct PendingSplice {
2174
- pub our_funding_contribution: i64,
2175
2173
funding_negotiation: Option<FundingNegotiation>,
2176
2174
2177
2175
/// The funding txid used in the `splice_locked` sent to the counterparty.
@@ -2775,86 +2773,6 @@ impl<SP: Deref> PendingV2Channel<SP>
2775
2773
where
2776
2774
SP::Target: SignerProvider,
2777
2775
{
2778
- /// Prepare and start interactive transaction negotiation.
2779
- /// `change_destination_opt` - Optional destination for optional change; if None,
2780
- /// default destination address is used.
2781
- /// If error occurs, it is caused by our side, not the counterparty.
2782
- #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled
2783
- #[rustfmt::skip]
2784
- fn begin_interactive_funding_tx_construction<ES: Deref>(
2785
- &mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey,
2786
- change_destination_opt: Option<ScriptBuf>,
2787
- ) -> Result<Option<InteractiveTxMessageSend>, AbortReason>
2788
- where ES::Target: EntropySource
2789
- {
2790
- debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_)));
2791
- debug_assert!(self.interactive_tx_constructor.is_none());
2792
-
2793
- let mut funding_inputs = Vec::new();
2794
- mem::swap(&mut self.funding_negotiation_context.our_funding_inputs, &mut funding_inputs);
2795
-
2796
- // TODO(splicing): Add prev funding tx as input, must be provided as a parameter
2797
-
2798
- // Add output for funding tx
2799
- // Note: For the error case when the inputs are insufficient, it will be handled after
2800
- // the `calculate_change_output_value` call below
2801
- let mut funding_outputs = Vec::new();
2802
-
2803
- let shared_funding_output = TxOut {
2804
- value: Amount::from_sat(self.funding.get_value_satoshis()),
2805
- script_pubkey: self.funding.get_funding_redeemscript().to_p2wsh(),
2806
- };
2807
-
2808
- // Optionally add change output
2809
- let change_script = if let Some(script) = change_destination_opt {
2810
- script
2811
- } else {
2812
- signer_provider.get_destination_script(self.context.channel_keys_id)
2813
- .map_err(|_err| AbortReason::InternalError("Error getting destination script"))?
2814
- };
2815
- let change_value_opt = calculate_change_output_value(
2816
- self.funding.is_outbound(), self.funding_negotiation_context.our_funding_satoshis,
2817
- &funding_inputs, None,
2818
- &shared_funding_output.script_pubkey, &funding_outputs,
2819
- self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
2820
- change_script.minimal_non_dust().to_sat(),
2821
- )?;
2822
- if let Some(change_value) = change_value_opt {
2823
- let mut change_output = TxOut {
2824
- value: Amount::from_sat(change_value),
2825
- script_pubkey: change_script,
2826
- };
2827
- let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
2828
- let change_output_fee = fee_for_weight(self.funding_negotiation_context.funding_feerate_sat_per_1000_weight, change_output_weight);
2829
- let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
2830
- // Check dust limit again
2831
- if change_value_decreased_with_fee > self.context.holder_dust_limit_satoshis {
2832
- change_output.value = Amount::from_sat(change_value_decreased_with_fee);
2833
- funding_outputs.push(change_output);
2834
- }
2835
- }
2836
-
2837
- let constructor_args = InteractiveTxConstructorArgs {
2838
- entropy_source,
2839
- holder_node_id,
2840
- counterparty_node_id: self.context.counterparty_node_id,
2841
- channel_id: self.context.channel_id(),
2842
- feerate_sat_per_kw: self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
2843
- is_initiator: self.funding.is_outbound(),
2844
- funding_tx_locktime: self.funding_negotiation_context.funding_tx_locktime,
2845
- inputs_to_contribute: funding_inputs,
2846
- shared_funding_input: None,
2847
- shared_funding_output: SharedOwnedOutput::new(shared_funding_output, self.funding_negotiation_context.our_funding_satoshis),
2848
- outputs_to_contribute: funding_outputs,
2849
- };
2850
- let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
2851
- let msg = tx_constructor.take_initiator_first_message();
2852
-
2853
- self.interactive_tx_constructor = Some(tx_constructor);
2854
-
2855
- Ok(msg)
2856
- }
2857
-
2858
2776
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2859
2777
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2860
2778
Some(ref mut tx_constructor) => tx_constructor
@@ -2934,7 +2852,6 @@ where
2934
2852
where
2935
2853
L::Target: Logger
2936
2854
{
2937
- let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis;
2938
2855
let transaction_number = self.unfunded_context.transaction_number();
2939
2856
2940
2857
let mut output_index = None;
@@ -2969,7 +2886,7 @@ where
2969
2886
};
2970
2887
2971
2888
let funding_ready_for_sig_event = if signing_session.local_inputs_count() == 0 {
2972
- debug_assert_eq!(our_funding_satoshis , 0);
2889
+ debug_assert_eq!(self.funding_negotiation_context.our_funding_contribution_satoshis , 0);
2973
2890
if signing_session.provide_holder_witnesses(self.context.channel_id, Vec::new()).is_err() {
2974
2891
debug_assert!(
2975
2892
false,
@@ -5874,28 +5791,107 @@ fn check_v2_funding_inputs_sufficient(
5874
5791
5875
5792
/// Context for negotiating channels (dual-funded V2 open, splicing)
5876
5793
pub(super) struct FundingNegotiationContext {
5794
+ /// Whether we initiated the funding negotiation.
5795
+ pub is_initiator: bool,
5877
5796
/// The amount in satoshis we will be contributing to the channel.
5878
- pub our_funding_satoshis: u64 ,
5797
+ pub our_funding_contribution_satoshis: i64 ,
5879
5798
/// The amount in satoshis our counterparty will be contributing to the channel.
5880
5799
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5881
- pub their_funding_satoshis : Option<u64 >,
5800
+ pub their_funding_contribution_satoshis : Option<i64 >,
5882
5801
/// The funding transaction locktime suggested by the initiator. If set by us, it is always set
5883
5802
/// to the current block height to align incentives against fee-sniping.
5884
5803
pub funding_tx_locktime: LockTime,
5885
5804
/// The feerate set by the initiator to be used for the funding transaction.
5886
5805
#[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled.
5887
5806
pub funding_feerate_sat_per_1000_weight: u32,
5888
5807
/// The funding inputs we will be contributing to the channel.
5889
- ///
5890
- /// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs`
5891
- /// minus any fees paid for our contributed weight. This means that change will never be generated
5892
- /// and the maximum value possible will go towards funding the channel.
5893
- ///
5894
- /// Note that this field may be emptied once the interactive negotiation has been started.
5895
5808
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5896
5809
pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
5897
5810
}
5898
5811
5812
+ impl FundingNegotiationContext {
5813
+ /// Prepare and start interactive transaction negotiation.
5814
+ /// `change_destination_opt` - Optional destination for optional change; if None,
5815
+ /// default destination address is used.
5816
+ /// If error occurs, it is caused by our side, not the counterparty.
5817
+ #[cfg(splicing)]
5818
+ fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
5819
+ self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
5820
+ entropy_source: &ES, holder_node_id: PublicKey, change_destination_opt: Option<ScriptBuf>,
5821
+ shared_funding_input: Option<SharedOwnedInput>,
5822
+ ) -> Result<InteractiveTxConstructor, AbortReason>
5823
+ where
5824
+ SP::Target: SignerProvider,
5825
+ ES::Target: EntropySource,
5826
+ {
5827
+ if shared_funding_input.is_some() {
5828
+ debug_assert!(matches!(context.channel_state, ChannelState::ChannelReady(_)));
5829
+ } else {
5830
+ debug_assert!(matches!(context.channel_state, ChannelState::NegotiatingFunding(_)));
5831
+ }
5832
+
5833
+ // Add output for funding tx
5834
+ // Note: For the error case when the inputs are insufficient, it will be handled after
5835
+ // the `calculate_change_output_value` call below
5836
+ let mut funding_outputs = Vec::new();
5837
+
5838
+ let shared_funding_output = TxOut {
5839
+ value: Amount::from_sat(funding.get_value_satoshis()),
5840
+ script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
5841
+ };
5842
+
5843
+ // Optionally add change output
5844
+ if self.our_funding_contribution_satoshis > 0 {
5845
+ let change_value_opt = calculate_change_output_value(
5846
+ &self,
5847
+ funding.channel_transaction_parameters.splice_parent_funding_txid.is_some(),
5848
+ &shared_funding_output.script_pubkey,
5849
+ &funding_outputs,
5850
+ context.holder_dust_limit_satoshis,
5851
+ )?;
5852
+ if let Some(change_value) = change_value_opt {
5853
+ let change_script = if let Some(script) = change_destination_opt {
5854
+ script
5855
+ } else {
5856
+ signer_provider.get_destination_script(context.channel_keys_id).map_err(
5857
+ |_err| AbortReason::InternalError("Error getting destination script"),
5858
+ )?
5859
+ };
5860
+ let mut change_output =
5861
+ TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
5862
+ let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
5863
+ let change_output_fee =
5864
+ fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
5865
+ let change_value_decreased_with_fee =
5866
+ change_value.saturating_sub(change_output_fee);
5867
+ // Check dust limit again
5868
+ if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
5869
+ change_output.value = Amount::from_sat(change_value_decreased_with_fee);
5870
+ funding_outputs.push(change_output);
5871
+ }
5872
+ }
5873
+ }
5874
+
5875
+ let constructor_args = InteractiveTxConstructorArgs {
5876
+ entropy_source,
5877
+ holder_node_id,
5878
+ counterparty_node_id: context.counterparty_node_id,
5879
+ channel_id: context.channel_id(),
5880
+ feerate_sat_per_kw: self.funding_feerate_sat_per_1000_weight,
5881
+ is_initiator: self.is_initiator,
5882
+ funding_tx_locktime: self.funding_tx_locktime,
5883
+ inputs_to_contribute: self.our_funding_inputs,
5884
+ shared_funding_input,
5885
+ shared_funding_output: SharedOwnedOutput::new(
5886
+ shared_funding_output,
5887
+ funding.value_to_self_msat / 1000,
5888
+ ),
5889
+ outputs_to_contribute: funding_outputs,
5890
+ };
5891
+ InteractiveTxConstructor::new(constructor_args)
5892
+ }
5893
+ }
5894
+
5899
5895
// Holder designates channel data owned for the benefit of the user client.
5900
5896
// Counterparty designates channel data owned by the another channel participant entity.
5901
5897
pub(super) struct FundedChannel<SP: Deref>
@@ -10418,11 +10414,13 @@ where
10418
10414
) -> Result<msgs::SpliceInit, APIError> {
10419
10415
// Check if a splice has been initiated already.
10420
10416
// Note: only a single outstanding splice is supported (per spec)
10421
- if let Some(splice_info) = &self.pending_splice {
10422
- return Err(APIError::APIMisuseError { err: format!(
10423
- "Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
10424
- self.context.channel_id(), splice_info.our_funding_contribution
10425
- )});
10417
+ if self.pending_splice.is_some() {
10418
+ return Err(APIError::APIMisuseError {
10419
+ err: format!(
10420
+ "Channel {} cannot be spliced, as it has already a splice pending",
10421
+ self.context.channel_id(),
10422
+ ),
10423
+ });
10426
10424
}
10427
10425
10428
10426
if !self.context.is_live() {
@@ -10455,7 +10453,6 @@ where
10455
10453
)})?;
10456
10454
10457
10455
self.pending_splice = Some(PendingSplice {
10458
- our_funding_contribution: our_funding_contribution_satoshis,
10459
10456
funding_negotiation: None,
10460
10457
sent_funding_txid: None,
10461
10458
received_funding_txid: None,
@@ -10492,9 +10489,10 @@ where
10492
10489
let our_funding_contribution_satoshis = 0i64;
10493
10490
10494
10491
// Check if a splice has been initiated already.
10495
- if let Some(splice_info) = & self.pending_splice {
10492
+ if self.pending_splice.is_some() {
10496
10493
return Err(ChannelError::Warn(format!(
10497
- "Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
10494
+ "Channel {} already has a splice pending",
10495
+ self.context.channel_id(),
10498
10496
)));
10499
10497
}
10500
10498
@@ -12105,9 +12103,10 @@ where
12105
12103
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
12106
12104
};
12107
12105
let funding_negotiation_context = FundingNegotiationContext {
12108
- our_funding_satoshis: funding_satoshis,
12106
+ is_initiator: true,
12107
+ our_funding_contribution_satoshis: funding_satoshis as i64,
12109
12108
// TODO(dual_funding) TODO(splicing) Include counterparty contribution, once that's enabled
12110
- their_funding_satoshis : None,
12109
+ their_funding_contribution_satoshis : None,
12111
12110
funding_tx_locktime,
12112
12111
funding_feerate_sat_per_1000_weight,
12113
12112
our_funding_inputs: funding_inputs,
@@ -12259,8 +12258,9 @@ where
12259
12258
context.channel_id = channel_id;
12260
12259
12261
12260
let funding_negotiation_context = FundingNegotiationContext {
12262
- our_funding_satoshis: our_funding_satoshis,
12263
- their_funding_satoshis: Some(msg.common_fields.funding_satoshis),
12261
+ is_initiator: false,
12262
+ our_funding_contribution_satoshis: our_funding_satoshis as i64,
12263
+ their_funding_contribution_satoshis: Some(msg.common_fields.funding_satoshis as i64),
12264
12264
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
12265
12265
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
12266
12266
our_funding_inputs: our_funding_inputs.clone(),
@@ -12362,7 +12362,8 @@ where
12362
12362
}),
12363
12363
channel_type: Some(self.funding.get_channel_type().clone()),
12364
12364
},
12365
- funding_satoshis: self.funding_negotiation_context.our_funding_satoshis,
12365
+ funding_satoshis: self.funding_negotiation_context.our_funding_contribution_satoshis
12366
+ as u64,
12366
12367
second_per_commitment_point,
12367
12368
require_confirmed_inputs: None,
12368
12369
}
0 commit comments