Skip to content

Commit 7c47dda

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 3e5d752 commit 7c47dda

File tree

2 files changed

+159
-70
lines changed

2 files changed

+159
-70
lines changed

lightning/src/ln/channel.rs

Lines changed: 135 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,6 +1729,19 @@ where
17291729
}
17301730
}
17311731

1732+
pub fn as_negotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, ChannelError> {
1733+
match &mut self.phase {
1734+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel()),
1735+
#[cfg(splicing)]
1736+
ChannelPhase::Funded(chan) => {
1737+
Ok(chan.as_renegotiating_channel().map_err(|err| ChannelError::Warn(err.into()))?)
1738+
},
1739+
_ => Err(ChannelError::Warn(
1740+
"Got a transaction negotiation message in an invalid phase".to_owned(),
1741+
)),
1742+
}
1743+
}
1744+
17321745
#[rustfmt::skip]
17331746
pub fn funding_signed<L: Deref>(
17341747
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
@@ -1767,9 +1780,11 @@ where
17671780
where
17681781
L::Target: Logger,
17691782
{
1770-
if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
1771-
let logger = WithChannelContext::from(logger, &chan.context, None);
1772-
chan.funding_tx_constructed(signing_session, &&logger)
1783+
let logger = WithChannelContext::from(logger, self.context(), None);
1784+
if let Ok(mut negotiating_channel) = self.as_negotiating_channel() {
1785+
let (commitment_signed, event) =
1786+
negotiating_channel.funding_tx_constructed(signing_session, &&logger)?;
1787+
Ok((commitment_signed, event))
17731788
} else {
17741789
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
17751790
}
@@ -2174,8 +2189,13 @@ impl FundingScope {
21742189
/// Info about a pending splice, used in the pre-splice channel
21752190
#[cfg(splicing)]
21762191
struct PendingSplice {
2192+
/// Intended contributions to the splice from our end
21772193
pub our_funding_contribution: i64,
21782194
funding: Option<FundingScope>,
2195+
funding_negotiation_context: FundingNegotiationContext,
2196+
/// The current interactive transaction construction session under negotiation.
2197+
interactive_tx_constructor: Option<InteractiveTxConstructor>,
2198+
interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
21792199

21802200
/// The funding txid used in the `splice_locked` sent to the counterparty.
21812201
sent_funding_txid: Option<Txid>,
@@ -2756,7 +2776,23 @@ where
27562776
}
27572777
}
27582778

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

2858-
self.interactive_tx_constructor = Some(tx_constructor);
2894+
*self.interactive_tx_constructor = Some(tx_constructor);
28592895

28602896
Ok(msg)
28612897
}
28622898

2863-
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2864-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2899+
pub(super) fn tx_add_input(
2900+
&mut self, msg: &msgs::TxAddInput,
2901+
) -> InteractiveTxMessageSendResult {
2902+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28652903
Some(ref mut tx_constructor) => tx_constructor
28662904
.handle_tx_add_input(msg)
28672905
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2872,8 +2910,10 @@ where
28722910
})
28732911
}
28742912

2875-
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> InteractiveTxMessageSendResult {
2876-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2913+
pub(super) fn tx_add_output(
2914+
&mut self, msg: &msgs::TxAddOutput,
2915+
) -> InteractiveTxMessageSendResult {
2916+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28772917
Some(ref mut tx_constructor) => tx_constructor
28782918
.handle_tx_add_output(msg)
28792919
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2884,8 +2924,10 @@ where
28842924
})
28852925
}
28862926

2887-
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> InteractiveTxMessageSendResult {
2888-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2927+
pub(super) fn tx_remove_input(
2928+
&mut self, msg: &msgs::TxRemoveInput,
2929+
) -> InteractiveTxMessageSendResult {
2930+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
28892931
Some(ref mut tx_constructor) => tx_constructor
28902932
.handle_tx_remove_input(msg)
28912933
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2896,10 +2938,10 @@ where
28962938
})
28972939
}
28982940

2899-
pub fn tx_remove_output(
2941+
pub(super) fn tx_remove_output(
29002942
&mut self, msg: &msgs::TxRemoveOutput,
29012943
) -> InteractiveTxMessageSendResult {
2902-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2944+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
29032945
Some(ref mut tx_constructor) => tx_constructor
29042946
.handle_tx_remove_output(msg)
29052947
.map_err(|reason| reason.into_tx_abort_msg(self.context.channel_id())),
@@ -2910,9 +2952,9 @@ where
29102952
})
29112953
}
29122954

2913-
pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2914-
let tx_constructor = match &mut self.interactive_tx_constructor {
2915-
Some(ref mut tx_constructor) => tx_constructor,
2955+
pub(super) fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2956+
let tx_constructor = match self.interactive_tx_constructor {
2957+
Some(tx_constructor) => tx_constructor,
29162958
None => {
29172959
let tx_abort = msgs::TxAbort {
29182960
channel_id: msg.channel_id,
@@ -2933,14 +2975,14 @@ where
29332975
}
29342976

29352977
#[rustfmt::skip]
2936-
pub fn funding_tx_constructed<L: Deref>(
2978+
fn funding_tx_constructed<L: Deref>(
29372979
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
29382980
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
29392981
where
29402982
L::Target: Logger
29412983
{
2942-
let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis;
2943-
let transaction_number = self.unfunded_context.transaction_number();
2984+
let our_funding_satoshis = self.funding_negotiation_context
2985+
.our_funding_satoshis;
29442986

29452987
let mut output_index = None;
29462988
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
@@ -2965,14 +3007,16 @@ where
29653007
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
29663008
)));
29673009
};
2968-
self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
3010+
self.funding
3011+
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
29693012

2970-
self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
3013+
self.context.assert_no_commitment_advancement(self.holder_commitment_transaction_number, "initial commitment_signed");
29713014
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
29723015
let commitment_signed = match commitment_signed {
29733016
Ok(commitment_signed) => commitment_signed,
29743017
Err(err) => {
2975-
self.funding.channel_transaction_parameters.funding_outpoint = None;
3018+
self.funding
3019+
.channel_transaction_parameters.funding_outpoint = None;
29763020
return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })));
29773021
},
29783022
};
@@ -3020,8 +3064,8 @@ where
30203064
self.context.channel_state = channel_state;
30213065

30223066
// Clear the interactive transaction constructor
3023-
self.interactive_tx_constructor.take();
3024-
self.interactive_tx_signing_session = Some(signing_session);
3067+
*self.interactive_tx_constructor = None;
3068+
*self.interactive_tx_signing_session = Some(signing_session);
30253069

30263070
Ok((commitment_signed, funding_ready_for_sig_event))
30273071
}
@@ -6059,6 +6103,42 @@ where
60596103
SP::Target: SignerProvider,
60606104
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner,
60616105
{
6106+
/// If we are in splicing/refunding, return a short-lived [`NegotiatingChannelView`].
6107+
#[cfg(splicing)]
6108+
fn as_renegotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, &'static str> {
6109+
if let Some(ref mut pending_splice) = &mut self.pending_splice {
6110+
if let Some(ref mut funding) = &mut pending_splice.funding {
6111+
if pending_splice.funding_negotiation_context.our_funding_satoshis != 0
6112+
|| pending_splice
6113+
.funding_negotiation_context
6114+
.their_funding_satoshis
6115+
.unwrap_or_default() != 0
6116+
{
6117+
Ok(NegotiatingChannelView {
6118+
context: &mut self.context,
6119+
funding,
6120+
funding_negotiation_context: &mut pending_splice
6121+
.funding_negotiation_context,
6122+
interactive_tx_constructor: &mut pending_splice.interactive_tx_constructor,
6123+
interactive_tx_signing_session: &mut pending_splice
6124+
.interactive_tx_signing_session,
6125+
holder_commitment_transaction_number: self
6126+
.holder_commitment_point
6127+
.transaction_number(),
6128+
})
6129+
} else {
6130+
Err("Received unexpected interactive transaction negotiation message: \
6131+
the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
6132+
}
6133+
} else {
6134+
Err("Received unexpected interactive transaction negotiation message: \
6135+
the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
6136+
}
6137+
} else {
6138+
Err("Received unexpected interactive transaction negotiation message: the channel is funded and not splicing")
6139+
}
6140+
}
6141+
60626142
#[rustfmt::skip]
60636143
fn check_remote_fee<F: Deref, L: Deref>(
60646144
channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,
@@ -10225,10 +10305,11 @@ where
1022510305
) -> Result<msgs::SpliceInit, APIError> {
1022610306
// Check if a splice has been initiated already.
1022710307
// Note: only a single outstanding splice is supported (per spec)
10228-
if let Some(splice_info) = &self.pending_splice {
10308+
if let Some(pending_splice) = &self.pending_splice {
1022910309
return Err(APIError::APIMisuseError { err: format!(
1023010310
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
10231-
self.context.channel_id(), splice_info.our_funding_contribution
10311+
self.context.channel_id(),
10312+
pending_splice.our_funding_contribution,
1023210313
)});
1023310314
}
1023410315

@@ -10260,10 +10341,26 @@ where
1026010341
"Insufficient inputs for splicing; channel ID {}, err {}",
1026110342
self.context.channel_id(), err,
1026210343
)})?;
10344+
// Convert inputs
10345+
let mut funding_inputs = Vec::new();
10346+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
10347+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(|_e| APIError::APIMisuseError { err: format!("Too large transaction")})?;
10348+
funding_inputs.push((tx_in.clone(), tx16));
10349+
}
1026310350

10351+
let funding_negotiation_context = FundingNegotiationContext {
10352+
our_funding_satoshis: 0, // set at later phase
10353+
their_funding_satoshis: None, // set at later phase
10354+
funding_tx_locktime: LockTime::from_consensus(locktime),
10355+
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
10356+
our_funding_inputs: funding_inputs,
10357+
};
1026410358
self.pending_splice = Some(PendingSplice {
1026510359
our_funding_contribution: our_funding_contribution_satoshis,
1026610360
funding: None,
10361+
funding_negotiation_context,
10362+
interactive_tx_constructor: None,
10363+
interactive_tx_signing_session: None,
1026710364
sent_funding_txid: None,
1026810365
received_funding_txid: None,
1026910366
});
@@ -12159,6 +12256,18 @@ where
1215912256
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
1216012257
self.generate_accept_channel_v2_message()
1216112258
}
12259+
12260+
/// Return a short-lived [`NegotiatingChannelView`].
12261+
fn as_negotiating_channel(&mut self) -> NegotiatingChannelView<SP> {
12262+
NegotiatingChannelView {
12263+
context: &mut self.context,
12264+
funding: &mut self.funding,
12265+
funding_negotiation_context: &mut self.funding_negotiation_context,
12266+
interactive_tx_constructor: &mut self.interactive_tx_constructor,
12267+
interactive_tx_signing_session: &mut self.interactive_tx_signing_session,
12268+
holder_commitment_transaction_number: self.unfunded_context.transaction_number(),
12269+
}
12270+
}
1216212271
}
1216312272

1216412273
// Unfunded channel utilities

0 commit comments

Comments
 (0)