@@ -1727,6 +1727,19 @@ where
17271727 }
17281728 }
17291729
1730+ pub fn as_negotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, ChannelError> {
1731+ match &mut self.phase {
1732+ ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel()),
1733+ #[cfg(splicing)]
1734+ ChannelPhase::Funded(chan) => {
1735+ Ok(chan.as_renegotiating_channel().map_err(|err| ChannelError::Warn(err.into()))?)
1736+ },
1737+ _ => Err(ChannelError::Warn(
1738+ "Got a transaction negotiation message in an invalid phase".to_owned(),
1739+ )),
1740+ }
1741+ }
1742+
17301743 #[rustfmt::skip]
17311744 pub fn funding_signed<L: Deref>(
17321745 &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
@@ -1765,9 +1778,11 @@ where
17651778 where
17661779 L::Target: Logger,
17671780 {
1768- if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
1769- let logger = WithChannelContext::from(logger, &chan.context, None);
1770- chan.funding_tx_constructed(signing_session, &&logger)
1781+ let logger = WithChannelContext::from(logger, self.context(), None);
1782+ if let Ok(mut negotiating_channel) = self.as_negotiating_channel() {
1783+ let (commitment_signed, event) =
1784+ negotiating_channel.funding_tx_constructed(signing_session, &&logger)?;
1785+ Ok((commitment_signed, event))
17711786 } else {
17721787 Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
17731788 }
@@ -2147,7 +2162,13 @@ impl FundingScope {
21472162/// Info about a pending splice, used in the pre-splice channel
21482163#[cfg(splicing)]
21492164struct PendingSplice {
2165+ /// Intended contributions to the splice from our end
21502166 pub our_funding_contribution: i64,
2167+ funding_scope: Option<FundingScope>,
2168+ funding_negotiation_context: FundingNegotiationContext,
2169+ /// The current interactive transaction construction session under negotiation.
2170+ interactive_tx_constructor: Option<InteractiveTxConstructor>,
2171+ interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
21512172
21522173 /// The funding txid used in the `splice_locked` sent to the counterparty.
21532174 sent_funding_txid: Option<Txid>,
@@ -2694,7 +2715,23 @@ where
26942715 }
26952716}
26962717
2697- impl<SP: Deref> PendingV2Channel<SP>
2718+ /// A short-lived subset view of a channel, used for V2 funding negotiation or re-negotiation.
2719+ /// Can be produced by:
2720+ /// - [`PendingV2Channel`], at V2 channel open, and
2721+ /// - [`FundedChannel`], when splicing.
2722+ pub struct NegotiatingChannelView<'a, SP: Deref>
2723+ where
2724+ SP::Target: SignerProvider,
2725+ {
2726+ context: &'a mut ChannelContext<SP>,
2727+ funding: &'a mut FundingScope,
2728+ funding_negotiation_context: &'a mut FundingNegotiationContext,
2729+ interactive_tx_constructor: &'a mut Option<InteractiveTxConstructor>,
2730+ interactive_tx_signing_session: &'a mut Option<InteractiveTxSigningSession>,
2731+ holder_commitment_transaction_number: u64,
2732+ }
2733+
2734+ impl<'a, SP: Deref> NegotiatingChannelView<'a, SP>
26982735where
26992736 SP::Target: SignerProvider,
27002737{
@@ -2788,13 +2825,15 @@ where
27882825 let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
27892826 let msg = tx_constructor.take_initiator_first_message();
27902827
2791- self.interactive_tx_constructor = Some(tx_constructor);
2828+ * self.interactive_tx_constructor = Some(tx_constructor);
27922829
27932830 Ok(msg)
27942831 }
27952832
2796- pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2797- InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2833+ pub(super) fn tx_add_input(
2834+ &mut self, msg: &msgs::TxAddInput,
2835+ ) -> InteractiveTxMessageSendResult {
2836+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
27982837 Some(ref mut tx_constructor) => tx_constructor
27992838 .handle_tx_add_input(msg)
28002839 .map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2805,8 +2844,10 @@ where
28052844 })
28062845 }
28072846
2808- pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> InteractiveTxMessageSendResult {
2809- InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2847+ pub(super) fn tx_add_output(
2848+ &mut self, msg: &msgs::TxAddOutput,
2849+ ) -> InteractiveTxMessageSendResult {
2850+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28102851 Some(ref mut tx_constructor) => tx_constructor
28112852 .handle_tx_add_output(msg)
28122853 .map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2817,8 +2858,10 @@ where
28172858 })
28182859 }
28192860
2820- pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> InteractiveTxMessageSendResult {
2821- InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2861+ pub(super) fn tx_remove_input(
2862+ &mut self, msg: &msgs::TxRemoveInput,
2863+ ) -> InteractiveTxMessageSendResult {
2864+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28222865 Some(ref mut tx_constructor) => tx_constructor
28232866 .handle_tx_remove_input(msg)
28242867 .map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2829,10 +2872,10 @@ where
28292872 })
28302873 }
28312874
2832- pub fn tx_remove_output(
2875+ pub(super) fn tx_remove_output(
28332876 &mut self, msg: &msgs::TxRemoveOutput,
28342877 ) -> InteractiveTxMessageSendResult {
2835- InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2878+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28362879 Some(ref mut tx_constructor) => tx_constructor
28372880 .handle_tx_remove_output(msg)
28382881 .map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2843,9 +2886,9 @@ where
28432886 })
28442887 }
28452888
2846- pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2847- let tx_constructor = match &mut self.interactive_tx_constructor {
2848- Some(ref mut tx_constructor) => tx_constructor,
2889+ pub(super) fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2890+ let tx_constructor = match self.interactive_tx_constructor {
2891+ Some(tx_constructor) => tx_constructor,
28492892 None => {
28502893 let tx_abort = msgs::TxAbort {
28512894 channel_id: msg.channel_id,
@@ -2866,14 +2909,14 @@ where
28662909 }
28672910
28682911 #[rustfmt::skip]
2869- pub fn funding_tx_constructed<L: Deref>(
2912+ fn funding_tx_constructed<L: Deref>(
28702913 &mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
28712914 ) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
28722915 where
28732916 L::Target: Logger
28742917 {
2875- let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis;
2876- let transaction_number = self.unfunded_context.transaction_number() ;
2918+ let our_funding_satoshis = self.funding_negotiation_context
2919+ .our_funding_satoshis ;
28772920
28782921 let mut output_index = None;
28792922 let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
@@ -2898,14 +2941,16 @@ where
28982941 ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
28992942 )));
29002943 };
2901- self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2944+ self.funding
2945+ .channel_transaction_parameters.funding_outpoint = Some(outpoint);
29022946
2903- self.context.assert_no_commitment_advancement(transaction_number , "initial commitment_signed");
2947+ self.context.assert_no_commitment_advancement(self.holder_commitment_transaction_number , "initial commitment_signed");
29042948 let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
29052949 let commitment_signed = match commitment_signed {
29062950 Ok(commitment_signed) => commitment_signed,
29072951 Err(err) => {
2908- self.funding.channel_transaction_parameters.funding_outpoint = None;
2952+ self.funding
2953+ .channel_transaction_parameters.funding_outpoint = None;
29092954 return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })));
29102955 },
29112956 };
@@ -2953,8 +2998,8 @@ where
29532998 self.context.channel_state = channel_state;
29542999
29553000 // Clear the interactive transaction constructor
2956- self.interactive_tx_constructor.take() ;
2957- self.interactive_tx_signing_session = Some(signing_session);
3001+ * self.interactive_tx_constructor = None ;
3002+ * self.interactive_tx_signing_session = Some(signing_session);
29583003
29593004 Ok((commitment_signed, funding_ready_for_sig_event))
29603005 }
@@ -5936,6 +5981,42 @@ where
59365981 SP::Target: SignerProvider,
59375982 <SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner,
59385983{
5984+ /// If we are in splicing/refunding, return a short-lived [`NegotiatingChannelView`].
5985+ #[cfg(splicing)]
5986+ fn as_renegotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, &'static str> {
5987+ if let Some(ref mut pending_splice) = &mut self.pending_splice {
5988+ if let Some(ref mut funding) = &mut pending_splice.funding_scope {
5989+ if pending_splice.funding_negotiation_context.our_funding_satoshis != 0
5990+ || pending_splice
5991+ .funding_negotiation_context
5992+ .their_funding_satoshis
5993+ .unwrap_or_default() != 0
5994+ {
5995+ Ok(NegotiatingChannelView {
5996+ context: &mut self.context,
5997+ funding,
5998+ funding_negotiation_context: &mut pending_splice
5999+ .funding_negotiation_context,
6000+ interactive_tx_constructor: &mut pending_splice.interactive_tx_constructor,
6001+ interactive_tx_signing_session: &mut pending_splice
6002+ .interactive_tx_signing_session,
6003+ holder_commitment_transaction_number: self
6004+ .holder_commitment_point
6005+ .transaction_number(),
6006+ })
6007+ } else {
6008+ Err("Received unexpected interactive transaction negotiation message: \
6009+ the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
6010+ }
6011+ } else {
6012+ Err("Received unexpected interactive transaction negotiation message: \
6013+ the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
6014+ }
6015+ } else {
6016+ Err("Received unexpected interactive transaction negotiation message: the channel is funded and not splicing")
6017+ }
6018+ }
6019+
59396020 #[rustfmt::skip]
59406021 fn check_remote_fee<F: Deref, L: Deref>(
59416022 channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,
@@ -9797,10 +9878,11 @@ where
97979878 ) -> Result<msgs::SpliceInit, APIError> {
97989879 // Check if a splice has been initiated already.
97999880 // Note: only a single outstanding splice is supported (per spec)
9800- if let Some(splice_info ) = &self.pending_splice {
9881+ if let Some(pending_splice ) = &self.pending_splice {
98019882 return Err(APIError::APIMisuseError { err: format!(
98029883 "Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
9803- self.context.channel_id(), splice_info.our_funding_contribution
9884+ self.context.channel_id(),
9885+ pending_splice.our_funding_contribution,
98049886 )});
98059887 }
98069888
@@ -9832,9 +9914,26 @@ where
98329914 "Insufficient inputs for splicing; channel ID {}, err {}",
98339915 self.context.channel_id(), err,
98349916 )})?;
9917+ // Convert inputs
9918+ let mut funding_inputs = Vec::new();
9919+ for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
9920+ let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(|_e| APIError::APIMisuseError { err: format!("Too large transaction")})?;
9921+ funding_inputs.push((tx_in.clone(), tx16));
9922+ }
98359923
9924+ let funding_negotiation_context = FundingNegotiationContext {
9925+ our_funding_satoshis: 0, // set at later phase
9926+ their_funding_satoshis: None, // set at later phase
9927+ funding_tx_locktime: LockTime::from_consensus(locktime),
9928+ funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
9929+ our_funding_inputs: funding_inputs,
9930+ };
98369931 self.pending_splice = Some(PendingSplice {
98379932 our_funding_contribution: our_funding_contribution_satoshis,
9933+ funding_scope: None,
9934+ funding_negotiation_context,
9935+ interactive_tx_constructor: None,
9936+ interactive_tx_signing_session: None,
98389937 sent_funding_txid: None,
98399938 received_funding_txid: None,
98409939 });
@@ -11706,6 +11805,18 @@ where
1170611805 pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
1170711806 self.generate_accept_channel_v2_message()
1170811807 }
11808+
11809+ /// Return a short-lived [`NegotiatingChannelView`].
11810+ fn as_negotiating_channel(&mut self) -> NegotiatingChannelView<SP> {
11811+ NegotiatingChannelView {
11812+ context: &mut self.context,
11813+ funding: &mut self.funding,
11814+ funding_negotiation_context: &mut self.funding_negotiation_context,
11815+ interactive_tx_constructor: &mut self.interactive_tx_constructor,
11816+ interactive_tx_signing_session: &mut self.interactive_tx_signing_session,
11817+ holder_commitment_transaction_number: self.unfunded_context.transaction_number(),
11818+ }
11819+ }
1170911820}
1171011821
1171111822// Unfunded channel utilities
0 commit comments