Skip to content

Commit a1433fe

Browse files
optout21jkczyz
authored andcommitted
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 1279a86 commit a1433fe

File tree

2 files changed

+156
-68
lines changed

2 files changed

+156
-68
lines changed

lightning/src/ln/channel.rs

Lines changed: 134 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,19 @@ where
17321732
}
17331733
}
17341734

1735+
pub fn as_negotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, ChannelError> {
1736+
match &mut self.phase {
1737+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel()),
1738+
#[cfg(splicing)]
1739+
ChannelPhase::Funded(chan) => {
1740+
Ok(chan.as_renegotiating_channel().map_err(|err| ChannelError::Warn(err.into()))?)
1741+
},
1742+
_ => Err(ChannelError::Warn(
1743+
"Got a transaction negotiation message in an invalid phase".to_owned(),
1744+
)),
1745+
}
1746+
}
1747+
17351748
#[rustfmt::skip]
17361749
pub fn funding_signed<L: Deref>(
17371750
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
@@ -1770,9 +1783,11 @@ where
17701783
where
17711784
L::Target: Logger,
17721785
{
1773-
if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
1774-
let logger = WithChannelContext::from(logger, &chan.context, None);
1775-
chan.funding_tx_constructed(signing_session, &&logger)
1786+
let logger = WithChannelContext::from(logger, self.context(), None);
1787+
if let Ok(mut negotiating_channel) = self.as_negotiating_channel() {
1788+
let (commitment_signed, event) =
1789+
negotiating_channel.funding_tx_constructed(signing_session, &&logger)?;
1790+
Ok((commitment_signed, event))
17761791
} else {
17771792
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
17781793
}
@@ -2175,8 +2190,13 @@ impl FundingScope {
21752190
/// Info about a pending splice, used in the pre-splice channel
21762191
#[cfg(splicing)]
21772192
struct PendingSplice {
2193+
/// Intended contributions to the splice from our end
21782194
pub our_funding_contribution: i64,
21792195
funding: Option<FundingScope>,
2196+
funding_negotiation_context: FundingNegotiationContext,
2197+
/// The current interactive transaction construction session under negotiation.
2198+
interactive_tx_constructor: Option<InteractiveTxConstructor>,
2199+
interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
21802200

21812201
/// The funding txid used in the `splice_locked` sent to the counterparty.
21822202
sent_funding_txid: Option<Txid>,
@@ -2757,7 +2777,23 @@ where
27572777
}
27582778
}
27592779

2760-
impl<SP: Deref> PendingV2Channel<SP>
2780+
/// A short-lived subset view of a channel, used for V2 funding negotiation or re-negotiation.
2781+
/// Can be produced by:
2782+
/// - [`PendingV2Channel`], at V2 channel open, and
2783+
/// - [`FundedChannel`], when splicing.
2784+
pub struct NegotiatingChannelView<'a, SP: Deref>
2785+
where
2786+
SP::Target: SignerProvider,
2787+
{
2788+
context: &'a mut ChannelContext<SP>,
2789+
funding: &'a mut FundingScope,
2790+
funding_negotiation_context: &'a mut FundingNegotiationContext,
2791+
interactive_tx_constructor: &'a mut Option<InteractiveTxConstructor>,
2792+
interactive_tx_signing_session: &'a mut Option<InteractiveTxSigningSession>,
2793+
holder_commitment_transaction_number: u64,
2794+
}
2795+
2796+
impl<'a, SP: Deref> NegotiatingChannelView<'a, SP>
27612797
where
27622798
SP::Target: SignerProvider,
27632799
{
@@ -2841,13 +2877,15 @@ where
28412877
let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
28422878
let msg = tx_constructor.take_initiator_first_message();
28432879

2844-
self.interactive_tx_constructor = Some(tx_constructor);
2880+
*self.interactive_tx_constructor = Some(tx_constructor);
28452881

28462882
Ok(msg)
28472883
}
28482884

2849-
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2850-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2885+
pub(super) fn tx_add_input(
2886+
&mut self, msg: &msgs::TxAddInput,
2887+
) -> InteractiveTxMessageSendResult {
2888+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28512889
Some(ref mut tx_constructor) => tx_constructor
28522890
.handle_tx_add_input(msg)
28532891
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2858,8 +2896,10 @@ where
28582896
})
28592897
}
28602898

2861-
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> InteractiveTxMessageSendResult {
2862-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2899+
pub(super) fn tx_add_output(
2900+
&mut self, msg: &msgs::TxAddOutput,
2901+
) -> InteractiveTxMessageSendResult {
2902+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28632903
Some(ref mut tx_constructor) => tx_constructor
28642904
.handle_tx_add_output(msg)
28652905
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2870,8 +2910,10 @@ where
28702910
})
28712911
}
28722912

2873-
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> InteractiveTxMessageSendResult {
2874-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2913+
pub(super) fn tx_remove_input(
2914+
&mut self, msg: &msgs::TxRemoveInput,
2915+
) -> InteractiveTxMessageSendResult {
2916+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28752917
Some(ref mut tx_constructor) => tx_constructor
28762918
.handle_tx_remove_input(msg)
28772919
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2882,10 +2924,10 @@ where
28822924
})
28832925
}
28842926

2885-
pub fn tx_remove_output(
2927+
pub(super) fn tx_remove_output(
28862928
&mut self, msg: &msgs::TxRemoveOutput,
28872929
) -> InteractiveTxMessageSendResult {
2888-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2930+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28892931
Some(ref mut tx_constructor) => tx_constructor
28902932
.handle_tx_remove_output(msg)
28912933
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2896,9 +2938,9 @@ where
28962938
})
28972939
}
28982940

2899-
pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2900-
let tx_constructor = match &mut self.interactive_tx_constructor {
2901-
Some(ref mut tx_constructor) => tx_constructor,
2941+
pub(super) fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2942+
let tx_constructor = match self.interactive_tx_constructor {
2943+
Some(tx_constructor) => tx_constructor,
29022944
None => {
29032945
let tx_abort = msgs::TxAbort {
29042946
channel_id: msg.channel_id,
@@ -2919,14 +2961,14 @@ where
29192961
}
29202962

29212963
#[rustfmt::skip]
2922-
pub fn funding_tx_constructed<L: Deref>(
2964+
fn funding_tx_constructed<L: Deref>(
29232965
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
29242966
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
29252967
where
29262968
L::Target: Logger
29272969
{
2928-
let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis;
2929-
let transaction_number = self.unfunded_context.transaction_number();
2970+
let our_funding_satoshis = self.funding_negotiation_context
2971+
.our_funding_satoshis;
29302972

29312973
let mut output_index = None;
29322974
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
@@ -2947,9 +2989,10 @@ where
29472989
let reason = ClosureReason::ProcessingError { err: msg.to_owned() };
29482990
return Err(ChannelError::Close((msg.to_owned(), reason)));
29492991
};
2950-
self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2992+
self.funding
2993+
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
29512994

2952-
self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2995+
self.context.assert_no_commitment_advancement(self.holder_commitment_transaction_number, "initial commitment_signed");
29532996
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
29542997
let commitment_signed = match commitment_signed {
29552998
Ok(commitment_signed) => commitment_signed,
@@ -3000,8 +3043,8 @@ where
30003043
self.context.channel_state = channel_state;
30013044

30023045
// Clear the interactive transaction constructor
3003-
self.interactive_tx_constructor.take();
3004-
self.interactive_tx_signing_session = Some(signing_session);
3046+
*self.interactive_tx_constructor = None;
3047+
*self.interactive_tx_signing_session = Some(signing_session);
30053048

30063049
Ok((commitment_signed, funding_ready_for_sig_event))
30073050
}
@@ -5997,6 +6040,42 @@ where
59976040
self.context.force_shutdown(&self.funding, closure_reason)
59986041
}
59996042

6043+
/// If we are in splicing/refunding, return a short-lived [`NegotiatingChannelView`].
6044+
#[cfg(splicing)]
6045+
fn as_renegotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, &'static str> {
6046+
if let Some(ref mut pending_splice) = &mut self.pending_splice {
6047+
if let Some(ref mut funding) = &mut pending_splice.funding {
6048+
if pending_splice.funding_negotiation_context.our_funding_satoshis != 0
6049+
|| pending_splice
6050+
.funding_negotiation_context
6051+
.their_funding_satoshis
6052+
.unwrap_or_default() != 0
6053+
{
6054+
Ok(NegotiatingChannelView {
6055+
context: &mut self.context,
6056+
funding,
6057+
funding_negotiation_context: &mut pending_splice
6058+
.funding_negotiation_context,
6059+
interactive_tx_constructor: &mut pending_splice.interactive_tx_constructor,
6060+
interactive_tx_signing_session: &mut pending_splice
6061+
.interactive_tx_signing_session,
6062+
holder_commitment_transaction_number: self
6063+
.holder_commitment_point
6064+
.transaction_number(),
6065+
})
6066+
} else {
6067+
Err("Received unexpected interactive transaction negotiation message: \
6068+
the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
6069+
}
6070+
} else {
6071+
Err("Received unexpected interactive transaction negotiation message: \
6072+
the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
6073+
}
6074+
} else {
6075+
Err("Received unexpected interactive transaction negotiation message: the channel is funded and not splicing")
6076+
}
6077+
}
6078+
60006079
#[rustfmt::skip]
60016080
fn check_remote_fee<F: Deref, L: Deref>(
60026081
channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,
@@ -10181,10 +10260,11 @@ where
1018110260
) -> Result<msgs::SpliceInit, APIError> {
1018210261
// Check if a splice has been initiated already.
1018310262
// Note: only a single outstanding splice is supported (per spec)
10184-
if let Some(splice_info) = &self.pending_splice {
10263+
if let Some(pending_splice) = &self.pending_splice {
1018510264
return Err(APIError::APIMisuseError { err: format!(
1018610265
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
10187-
self.context.channel_id(), splice_info.our_funding_contribution
10266+
self.context.channel_id(),
10267+
pending_splice.our_funding_contribution,
1018810268
)});
1018910269
}
1019010270

@@ -10216,10 +10296,27 @@ where
1021610296
"Insufficient inputs for splicing; channel ID {}, err {}",
1021710297
self.context.channel_id(), err,
1021810298
)})?;
10299+
// Convert inputs
10300+
let mut funding_inputs = Vec::new();
10301+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
10302+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(|_e| APIError::APIMisuseError { err: format!("Too large transaction")})?;
10303+
funding_inputs.push((tx_in.clone(), tx16));
10304+
}
1021910305

10306+
let funding_negotiation_context = FundingNegotiationContext {
10307+
is_initiator: true,
10308+
our_funding_satoshis: 0, // set at later phase
10309+
their_funding_satoshis: None, // set at later phase
10310+
funding_tx_locktime: LockTime::from_consensus(locktime),
10311+
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
10312+
our_funding_inputs: funding_inputs,
10313+
};
1022010314
self.pending_splice = Some(PendingSplice {
1022110315
our_funding_contribution: our_funding_contribution_satoshis,
1022210316
funding: None,
10317+
funding_negotiation_context,
10318+
interactive_tx_constructor: None,
10319+
interactive_tx_signing_session: None,
1022310320
sent_funding_txid: None,
1022410321
received_funding_txid: None,
1022510322
});
@@ -12147,6 +12244,18 @@ where
1214712244
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
1214812245
self.generate_accept_channel_v2_message()
1214912246
}
12247+
12248+
/// Return a short-lived [`NegotiatingChannelView`].
12249+
fn as_negotiating_channel(&mut self) -> NegotiatingChannelView<SP> {
12250+
NegotiatingChannelView {
12251+
context: &mut self.context,
12252+
funding: &mut self.funding,
12253+
funding_negotiation_context: &mut self.funding_negotiation_context,
12254+
interactive_tx_constructor: &mut self.interactive_tx_constructor,
12255+
interactive_tx_signing_session: &mut self.interactive_tx_signing_session,
12256+
holder_commitment_transaction_number: self.unfunded_context.transaction_number(),
12257+
}
12258+
}
1215012259
}
1215112260

1215212261
// Unfunded channel utilities

0 commit comments

Comments
 (0)