Skip to content

Commit 78e2287

Browse files
committed
Introduce NegotiatingChannelView to bridge Funded and PendingV2
Introduce struct NegotiatingChannelView to perform transaction negotiation logic, on top of either PendingV2Channel (dual-funded channel open) or FundedChannel (splicing).
1 parent 1a193c7 commit 78e2287

File tree

2 files changed

+161
-70
lines changed

2 files changed

+161
-70
lines changed

lightning/src/ln/channel.rs

Lines changed: 137 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
21492164
struct 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>
26982735
where
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

Comments
 (0)