Skip to content

Commit d3c342c

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 7bce024 commit d3c342c

File tree

2 files changed

+142
-61
lines changed

2 files changed

+142
-61
lines changed

lightning/src/ln/channel.rs

Lines changed: 118 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,16 @@ impl<SP: Deref> Channel<SP> where
15821582
}
15831583
}
15841584

1585+
pub fn as_negotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, ChannelError> {
1586+
match &mut self.phase {
1587+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel()),
1588+
#[cfg(splicing)]
1589+
ChannelPhase::Funded(chan) => Ok(chan.as_renegotiating_channel()
1590+
.map_err(|err| ChannelError::Warn(err.into()))?),
1591+
_ => Err(ChannelError::Warn("Got a transaction negotiation message in an invalid phase".to_owned())),
1592+
}
1593+
}
1594+
15851595
pub fn funding_signed<L: Deref>(
15861596
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
15871597
) -> Result<(&mut FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), ChannelError>
@@ -1619,9 +1629,10 @@ impl<SP: Deref> Channel<SP> where
16191629
where
16201630
L::Target: Logger
16211631
{
1622-
if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
1623-
let logger = WithChannelContext::from(logger, &chan.context, None);
1624-
chan.funding_tx_constructed(signing_session, &&logger)
1632+
let logger = WithChannelContext::from(logger, self.context(), None);
1633+
if let Ok(mut negotiating_channel) = self.as_negotiating_channel() {
1634+
let (commitment_signed, event) = negotiating_channel.funding_tx_constructed(signing_session, &&logger)?;
1635+
Ok((commitment_signed, event))
16251636
} else {
16261637
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
16271638
}
@@ -1935,7 +1946,13 @@ impl FundingScope {
19351946
/// Info about a pending splice, used in the pre-splice channel
19361947
#[cfg(splicing)]
19371948
struct PendingSplice {
1949+
/// Intended contributions to the splice from our end
19381950
pub our_funding_contribution: i64,
1951+
funding_scope: Option<FundingScope>,
1952+
funding_negotiation_context: FundingNegotiationContext,
1953+
/// The current interactive transaction construction session under negotiation.
1954+
interactive_tx_constructor: Option<InteractiveTxConstructor>,
1955+
interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
19391956
}
19401957

19411958
/// Contains everything about the channel including state, and various flags.
@@ -2432,7 +2449,20 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where
24322449
}
24332450
}
24342451

2435-
impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2452+
/// A short-lived subset view of a channel, used for V2 funding negotiation or re-negotiation.
2453+
/// Can be produced by:
2454+
/// - [`PendingV2Channel`], at V2 channel open, and
2455+
/// - [`FundedChannel`], when splicing.
2456+
pub struct NegotiatingChannelView<'a, SP: Deref> where SP::Target: SignerProvider {
2457+
context: &'a mut ChannelContext<SP>,
2458+
funding: &'a mut FundingScope,
2459+
funding_negotiation_context: &'a mut FundingNegotiationContext,
2460+
interactive_tx_constructor: &'a mut Option<InteractiveTxConstructor>,
2461+
interactive_tx_signing_session: &'a mut Option<InteractiveTxSigningSession>,
2462+
holder_commitment_transaction_number: u64,
2463+
}
2464+
2465+
impl<'a, SP: Deref> NegotiatingChannelView<'a, SP> where SP::Target: SignerProvider {
24362466
/// Prepare and start interactive transaction negotiation.
24372467
/// `change_destination_opt` - Optional destination for optional change; if None,
24382468
/// default destination address is used.
@@ -2522,13 +2552,13 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25222552
let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
25232553
let msg = tx_constructor.take_initiator_first_message();
25242554

2525-
self.interactive_tx_constructor = Some(tx_constructor);
2555+
*self.interactive_tx_constructor = Some(tx_constructor);
25262556

25272557
Ok(msg)
25282558
}
25292559

2530-
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2531-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2560+
pub(super) fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2561+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25322562
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
25332563
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25342564
None => Err(msgs::TxAbort {
@@ -2538,8 +2568,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25382568
})
25392569
}
25402570

2541-
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
2542-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2571+
pub(super) fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
2572+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25432573
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
25442574
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25452575
None => Err(msgs::TxAbort {
@@ -2549,8 +2579,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25492579
})
25502580
}
25512581

2552-
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
2553-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2582+
pub(super) fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
2583+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25542584
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_input(msg).map_err(
25552585
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25562586
None => Err(msgs::TxAbort {
@@ -2560,8 +2590,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25602590
})
25612591
}
25622592

2563-
pub fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
2564-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2593+
pub(super) fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
2594+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25652595
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_output(msg).map_err(
25662596
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25672597
None => Err(msgs::TxAbort {
@@ -2571,9 +2601,9 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25712601
})
25722602
}
25732603

2574-
pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2575-
let tx_constructor = match &mut self.interactive_tx_constructor {
2576-
Some(ref mut tx_constructor) => tx_constructor,
2604+
pub(super) fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2605+
let tx_constructor = match self.interactive_tx_constructor {
2606+
Some(tx_constructor) => tx_constructor,
25772607
None => {
25782608
let tx_abort = msgs::TxAbort {
25792609
channel_id: msg.channel_id,
@@ -2593,14 +2623,14 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25932623
HandleTxCompleteResult(Ok(tx_complete))
25942624
}
25952625

2596-
pub fn funding_tx_constructed<L: Deref>(
2626+
fn funding_tx_constructed<L: Deref>(
25972627
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
25982628
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
25992629
where
26002630
L::Target: Logger
26012631
{
2602-
let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis;
2603-
let transaction_number = self.unfunded_context.transaction_number();
2632+
let our_funding_satoshis = self.funding_negotiation_context
2633+
.our_funding_satoshis;
26042634

26052635
let mut output_index = None;
26062636
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
@@ -2625,14 +2655,16 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
26252655
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
26262656
)));
26272657
};
2628-
self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
2658+
self.funding
2659+
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
26292660

2630-
self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2661+
self.context.assert_no_commitment_advancement(self.holder_commitment_transaction_number, "initial commitment_signed");
26312662
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
26322663
let commitment_signed = match commitment_signed {
26332664
Ok(commitment_signed) => commitment_signed,
26342665
Err(err) => {
2635-
self.funding.channel_transaction_parameters.funding_outpoint = None;
2666+
self.funding
2667+
.channel_transaction_parameters.funding_outpoint = None;
26362668
return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) })));
26372669
},
26382670
};
@@ -2680,8 +2712,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
26802712
self.context.channel_state = channel_state;
26812713

26822714
// Clear the interactive transaction constructor
2683-
self.interactive_tx_constructor.take();
2684-
self.interactive_tx_signing_session = Some(signing_session);
2715+
*self.interactive_tx_constructor = None;
2716+
*self.interactive_tx_signing_session = Some(signing_session);
26852717

26862718
Ok((commitment_signed, funding_ready_for_sig_event))
26872719
}
@@ -5262,6 +5294,36 @@ impl<SP: Deref> FundedChannel<SP> where
52625294
SP::Target: SignerProvider,
52635295
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
52645296
{
5297+
/// If we are in splicing/refunding, return a short-lived [`NegotiatingChannelView`].
5298+
#[cfg(splicing)]
5299+
fn as_renegotiating_channel(&mut self) -> Result<NegotiatingChannelView<SP>, &'static str> {
5300+
if let Some(ref mut pending_splice) = &mut self.pending_splice {
5301+
if let Some(ref mut funding) = &mut pending_splice.funding_scope {
5302+
if
5303+
pending_splice.funding_negotiation_context.our_funding_satoshis != 0 ||
5304+
pending_splice.funding_negotiation_context.their_funding_satoshis.unwrap_or_default() != 0
5305+
{
5306+
Ok(NegotiatingChannelView {
5307+
context: &mut self.context,
5308+
funding,
5309+
funding_negotiation_context: &mut pending_splice.funding_negotiation_context,
5310+
interactive_tx_constructor: &mut pending_splice.interactive_tx_constructor,
5311+
interactive_tx_signing_session: &mut pending_splice.interactive_tx_signing_session,
5312+
holder_commitment_transaction_number: self.holder_commitment_point.transaction_number(),
5313+
})
5314+
} else {
5315+
Err("Received unexpected interactive transaction negotiation message: \
5316+
the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
5317+
}
5318+
} else {
5319+
Err("Received unexpected interactive transaction negotiation message: \
5320+
the channel is splicing, but splice_init/splice_ack has not been exchanged yet")
5321+
}
5322+
} else {
5323+
Err("Received unexpected interactive transaction negotiation message: the channel is funded and not splicing")
5324+
}
5325+
}
5326+
52655327
fn check_remote_fee<F: Deref, L: Deref>(
52665328
channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,
52675329
feerate_per_kw: u32, cur_feerate_per_kw: Option<u32>, logger: &L
@@ -8895,10 +8957,11 @@ impl<SP: Deref> FundedChannel<SP> where
88958957
) -> Result<msgs::SpliceInit, APIError> {
88968958
// Check if a splice has been initiated already.
88978959
// Note: only a single outstanding splice is supported (per spec)
8898-
if let Some(splice_info) = &self.pending_splice {
8960+
if let Some(pending_splice) = &self.pending_splice {
88998961
return Err(APIError::APIMisuseError { err: format!(
89008962
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
8901-
self.context.channel_id(), splice_info.our_funding_contribution
8963+
self.context.channel_id(),
8964+
pending_splice.our_funding_contribution,
89028965
)});
89038966
}
89048967

@@ -8930,9 +8993,26 @@ impl<SP: Deref> FundedChannel<SP> where
89308993
"Insufficient inputs for splicing; channel ID {}, err {}",
89318994
self.context.channel_id(), err,
89328995
)})?;
8996+
// Convert inputs
8997+
let mut funding_inputs = Vec::new();
8998+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
8999+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(|_e| APIError::APIMisuseError { err: format!("Too large transaction")})?;
9000+
funding_inputs.push((tx_in.clone(), tx16));
9001+
}
89339002

9003+
let funding_negotiation_context = FundingNegotiationContext {
9004+
our_funding_satoshis: 0, // set at later phase
9005+
their_funding_satoshis: None, // set at later phase
9006+
funding_tx_locktime: LockTime::from_consensus(locktime),
9007+
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
9008+
our_funding_inputs: funding_inputs,
9009+
};
89349010
self.pending_splice = Some(PendingSplice {
89359011
our_funding_contribution: our_funding_contribution_satoshis,
9012+
funding_scope: None,
9013+
funding_negotiation_context,
9014+
interactive_tx_constructor: None,
9015+
interactive_tx_signing_session: None,
89369016
});
89379017

89389018
let msg = self.get_splice_init(our_funding_contribution_satoshis, funding_feerate_per_kw, locktime);
@@ -10652,6 +10732,18 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
1065210732
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
1065310733
self.generate_accept_channel_v2_message()
1065410734
}
10735+
10736+
/// Return a short-lived [`NegotiatingChannelView`].
10737+
fn as_negotiating_channel(&mut self) -> NegotiatingChannelView<SP> {
10738+
NegotiatingChannelView {
10739+
context: &mut self.context,
10740+
funding: &mut self.funding,
10741+
funding_negotiation_context: &mut self.funding_negotiation_context,
10742+
interactive_tx_constructor: &mut self.interactive_tx_constructor,
10743+
interactive_tx_signing_session: &mut self.interactive_tx_signing_session,
10744+
holder_commitment_transaction_number: self.unfunded_context.transaction_number(),
10745+
}
10746+
}
1065510747
}
1065610748

1065710749
// Unfunded channel utilities

lightning/src/ln/channelmanager.rs

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8636,7 +8636,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
86368636
}
86378637

86388638
#[rustfmt::skip]
8639-
fn internal_tx_msg<HandleTxMsgFn: Fn(&mut Channel<SP>) -> Result<MessageSendEvent, &'static str>>(
8639+
fn internal_tx_msg<HandleTxMsgFn: Fn(&mut Channel<SP>) -> Result<MessageSendEvent, ChannelError>>(
86408640
&self, counterparty_node_id: &PublicKey, channel_id: ChannelId, tx_msg_handler: HandleTxMsgFn
86418641
) -> Result<(), MsgHandleErrInternal> {
86428642
let per_peer_state = self.per_peer_state.read().unwrap();
@@ -8654,9 +8654,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
86548654
let channel = chan_entry.get_mut();
86558655
let msg_send_event = match tx_msg_handler(channel) {
86568656
Ok(msg_send_event) => msg_send_event,
8657-
Err(tx_msg_str) => return Err(MsgHandleErrInternal::from_chan_no_close(ChannelError::Warn(
8658-
format!("Got a {tx_msg_str} message with no interactive transaction construction expected or in-progress")
8659-
), channel_id)),
8657+
Err(err) => return Err(MsgHandleErrInternal::from_chan_no_close(err, channel_id)),
86608658
};
86618659
peer_state.pending_msg_events.push(msg_send_event);
86628660
Ok(())
@@ -8674,48 +8672,40 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
86748672
&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddInput,
86758673
) -> Result<(), MsgHandleErrInternal> {
86768674
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel<SP>| {
8677-
match channel.as_unfunded_v2_mut() {
8678-
Some(unfunded_channel) => {
8679-
Ok(unfunded_channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id))
8680-
},
8681-
None => Err("tx_add_input"),
8682-
}
8675+
Ok(channel
8676+
.as_negotiating_channel()?
8677+
.tx_add_input(msg)
8678+
.into_msg_send_event(counterparty_node_id))
86838679
})
86848680
}
86858681

86868682
#[rustfmt::skip]
86878683
fn internal_tx_add_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxAddOutput) -> Result<(), MsgHandleErrInternal> {
86888684
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel<SP>| {
8689-
match channel.as_unfunded_v2_mut() {
8690-
Some(unfunded_channel) => {
8691-
Ok(unfunded_channel.tx_add_output(msg).into_msg_send_event(counterparty_node_id))
8692-
},
8693-
None => Err("tx_add_output"),
8694-
}
8685+
Ok(channel.as_negotiating_channel()?
8686+
.tx_add_output(msg)
8687+
.into_msg_send_event(counterparty_node_id)
8688+
)
86958689
})
86968690
}
86978691

86988692
#[rustfmt::skip]
86998693
fn internal_tx_remove_input(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveInput) -> Result<(), MsgHandleErrInternal> {
87008694
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel<SP>| {
8701-
match channel.as_unfunded_v2_mut() {
8702-
Some(unfunded_channel) => {
8703-
Ok(unfunded_channel.tx_remove_input(msg).into_msg_send_event(counterparty_node_id))
8704-
},
8705-
None => Err("tx_remove_input"),
8706-
}
8695+
Ok(channel.as_negotiating_channel()?
8696+
.tx_remove_input(msg)
8697+
.into_msg_send_event(counterparty_node_id)
8698+
)
87078699
})
87088700
}
87098701

87108702
#[rustfmt::skip]
87118703
fn internal_tx_remove_output(&self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveOutput) -> Result<(), MsgHandleErrInternal> {
87128704
self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel<SP>| {
8713-
match channel.as_unfunded_v2_mut() {
8714-
Some(unfunded_channel) => {
8715-
Ok(unfunded_channel.tx_remove_output(msg).into_msg_send_event(counterparty_node_id))
8716-
},
8717-
None => Err("tx_remove_output"),
8718-
}
8705+
Ok(channel.as_negotiating_channel()?
8706+
.tx_remove_output(msg)
8707+
.into_msg_send_event(counterparty_node_id)
8708+
)
87198709
})
87208710
}
87218711

@@ -8733,14 +8723,13 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
87338723
let peer_state = &mut *peer_state_lock;
87348724
match peer_state.channel_by_id.entry(msg.channel_id) {
87358725
hash_map::Entry::Occupied(mut chan_entry) => {
8736-
let (msg_send_event_opt, signing_session_opt) = match chan_entry.get_mut().as_unfunded_v2_mut() {
8737-
Some(chan) => chan.tx_complete(msg)
8726+
let (msg_send_event_opt, signing_session_opt) = match chan_entry.get_mut().as_negotiating_channel() {
8727+
Ok(mut negotiating_channel) => negotiating_channel
8728+
.tx_complete(msg)
87388729
.into_msg_send_event_or_signing_session(counterparty_node_id),
8739-
None => try_channel_entry!(self, peer_state, Err(ChannelError::Close(
8740-
(
8741-
"Got a tx_complete message with no interactive transaction construction expected or in-progress".into(),
8742-
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8743-
))), chan_entry)
8730+
Err(err) => {
8731+
try_channel_entry!(self, peer_state, Err(err), chan_entry)
8732+
}
87448733
};
87458734
if let Some(msg_send_event) = msg_send_event_opt {
87468735
peer_state.pending_msg_events.push(msg_send_event);

0 commit comments

Comments
 (0)