Skip to content

Commit fa7f7df

Browse files
committed
Introduce NegotiatingV2ChannelView to bridge Funded and PendingV2
Introduce struct NegotiatingV2ChannelView to perform transaction negotiation logic, on top of both PendingV2Channel (dual-funded channel open) and FundedChannel (splicing).
1 parent b614d97 commit fa7f7df

File tree

2 files changed

+179
-61
lines changed

2 files changed

+179
-61
lines changed

lightning/src/ln/channel.rs

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

1585+
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> Result<InteractiveTxMessageSendResult, ChannelError> {
1586+
match &mut self.phase {
1587+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel().tx_add_input(msg)),
1588+
#[cfg(splicing)]
1589+
ChannelPhase::Funded(chan) => Ok(chan.as_renegotiating_channel()
1590+
.map_err(|err| ChannelError::Warn(err.into()))?
1591+
.tx_add_input(msg)),
1592+
_ => Err(ChannelError::Warn("Got tx_add_input in an invalid phase".to_owned())),
1593+
}
1594+
}
1595+
1596+
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput) -> Result<InteractiveTxMessageSendResult, ChannelError> {
1597+
match &mut self.phase {
1598+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel().tx_add_output(msg)),
1599+
#[cfg(splicing)]
1600+
ChannelPhase::Funded(chan) => Ok(chan.as_renegotiating_channel()
1601+
.map_err(|err| ChannelError::Warn(err.into()))?
1602+
.tx_add_output(msg)),
1603+
_ => Err(ChannelError::Warn("Got tx_add_output in an invalid phase".to_owned())),
1604+
}
1605+
}
1606+
1607+
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput) -> Result<InteractiveTxMessageSendResult, ChannelError> {
1608+
match &mut self.phase {
1609+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel().tx_remove_input(msg)),
1610+
#[cfg(splicing)]
1611+
ChannelPhase::Funded(chan) => Ok(chan.as_renegotiating_channel()
1612+
.map_err(|err| ChannelError::Warn(err.into()))?
1613+
.tx_remove_input(msg)),
1614+
_ => Err(ChannelError::Warn("Got tx_remove_input in an invalid phase".to_owned())),
1615+
}
1616+
}
1617+
1618+
pub fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput) -> Result<InteractiveTxMessageSendResult, ChannelError> {
1619+
match &mut self.phase {
1620+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel().tx_remove_output(msg)),
1621+
#[cfg(splicing)]
1622+
ChannelPhase::Funded(chan) => Ok(chan.as_renegotiating_channel()
1623+
.map_err(|err| ChannelError::Warn(err.into()))?
1624+
.tx_remove_output(msg)),
1625+
_ => Err(ChannelError::Warn("Got tx_remove_output in an invalid phase".to_owned())),
1626+
}
1627+
}
1628+
1629+
pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> Result<HandleTxCompleteResult, ChannelError> {
1630+
match &mut self.phase {
1631+
ChannelPhase::UnfundedV2(chan) => Ok(chan.as_negotiating_channel().tx_complete(msg)),
1632+
#[cfg(splicing)]
1633+
ChannelPhase::Funded(chan) => Ok(chan.as_renegotiating_channel()
1634+
.map_err(|err| ChannelError::Warn(err.into()))?
1635+
.tx_complete(msg)),
1636+
_ => Err(ChannelError::Warn("Got tx_complete in an invalid phase".to_owned())),
1637+
}
1638+
}
1639+
15851640
pub fn funding_signed<L: Deref>(
15861641
&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
15871642
) -> Result<(&mut FundedChannel<SP>, ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>), ChannelError>
@@ -1621,7 +1676,7 @@ impl<SP: Deref> Channel<SP> where
16211676
{
16221677
if let ChannelPhase::UnfundedV2(chan) = &mut self.phase {
16231678
let logger = WithChannelContext::from(logger, &chan.context, None);
1624-
chan.funding_tx_constructed(signing_session, &&logger)
1679+
chan.as_negotiating_channel().funding_tx_constructed(signing_session, &&logger)
16251680
} else {
16261681
Err(ChannelError::Warn("Got a tx_complete message with no interactive transaction construction expected or in-progress".to_owned()))
16271682
}
@@ -1932,10 +1987,19 @@ impl FundingScope {
19321987
}
19331988
}
19341989

1935-
/// Info about a pending splice, used in the pre-splice channel
1990+
/// Info about a pending splice
19361991
#[cfg(splicing)]
19371992
struct PendingSplice {
1993+
/// Intended contributions to the splice from our end
19381994
pub our_funding_contribution: i64,
1995+
/// Set when splice_ack has been processed (on the initiator side),
1996+
/// used to prevent processing of multiple splice_ack's.
1997+
awaiting_splice_ack: bool,
1998+
funding_scope: Option<FundingScope>,
1999+
funding_negotiation_context: FundingNegotiationContext,
2000+
/// The current interactive transaction construction session under negotiation.
2001+
interactive_tx_constructor: Option<InteractiveTxConstructor>,
2002+
interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
19392003
}
19402004

19412005
/// Contains everything about the channel including state, and various flags.
@@ -2399,10 +2463,12 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
23992463
}
24002464

24012465
impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where SP::Target: SignerProvider {
2466+
#[inline]
24022467
fn context(&self) -> &ChannelContext<SP> {
24032468
&self.context
24042469
}
24052470

2471+
#[inline]
24062472
fn context_mut(&mut self) -> &mut ChannelContext<SP> {
24072473
&mut self.context
24082474
}
@@ -2432,7 +2498,21 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where
24322498
}
24332499
}
24342500

2435-
impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
2501+
/// A short-lived subset view of a channel, used for V2 funding negotiation or re-negotiation.
2502+
/// Can be produced by:
2503+
/// - [`PendingV2Channel`], at V2 channel open, and
2504+
/// - [`FundedChannel`], when splicing.
2505+
struct NegotiatingV2ChannelView<'a, SP: Deref> where SP::Target: SignerProvider {
2506+
context: &'a mut ChannelContext<SP>,
2507+
funding: &'a mut FundingScope,
2508+
funding_negotiation_context: &'a mut FundingNegotiationContext,
2509+
interactive_tx_constructor: &'a mut Option<InteractiveTxConstructor>,
2510+
interactive_tx_signing_session: &'a mut Option<InteractiveTxSigningSession>,
2511+
holder_commitment_transaction_number: u64,
2512+
is_splice: bool,
2513+
}
2514+
2515+
impl<'a, SP: Deref> NegotiatingV2ChannelView<'a, SP> where SP::Target: SignerProvider {
24362516
/// Prepare and start interactive transaction negotiation.
24372517
/// `change_destination_opt` - Optional destination for optional change; if None,
24382518
/// default destination address is used.
@@ -2522,13 +2602,13 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25222602
let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?;
25232603
let msg = tx_constructor.take_initiator_first_message();
25242604

2525-
self.interactive_tx_constructor = Some(tx_constructor);
2605+
*self.interactive_tx_constructor = Some(tx_constructor);
25262606

25272607
Ok(msg)
25282608
}
25292609

2530-
pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2531-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2610+
fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
2611+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25322612
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
25332613
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25342614
None => Err(msgs::TxAbort {
@@ -2538,8 +2618,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25382618
})
25392619
}
25402620

2541-
pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
2542-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2621+
fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
2622+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25432623
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
25442624
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25452625
None => Err(msgs::TxAbort {
@@ -2549,8 +2629,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25492629
})
25502630
}
25512631

2552-
pub fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
2553-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2632+
fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
2633+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25542634
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_input(msg).map_err(
25552635
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25562636
None => Err(msgs::TxAbort {
@@ -2560,8 +2640,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25602640
})
25612641
}
25622642

2563-
pub fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
2564-
InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor {
2643+
fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
2644+
InteractiveTxMessageSendResult(match self.interactive_tx_constructor {
25652645
Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_output(msg).map_err(
25662646
|reason| reason.into_tx_abort_msg(self.context.channel_id())),
25672647
None => Err(msgs::TxAbort {
@@ -2571,9 +2651,9 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25712651
})
25722652
}
25732653

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,
2654+
fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
2655+
let tx_constructor = match self.interactive_tx_constructor {
2656+
Some(tx_constructor) => tx_constructor,
25772657
None => {
25782658
let tx_abort = msgs::TxAbort {
25792659
channel_id: msg.channel_id,
@@ -2593,14 +2673,14 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
25932673
HandleTxCompleteResult(Ok(tx_complete))
25942674
}
25952675

2596-
pub fn funding_tx_constructed<L: Deref>(
2676+
fn funding_tx_constructed<L: Deref>(
25972677
&mut self, mut signing_session: InteractiveTxSigningSession, logger: &L
25982678
) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError>
25992679
where
26002680
L::Target: Logger
26012681
{
2602-
let our_funding_satoshis = self.funding_negotiation_context.our_funding_satoshis;
2603-
let transaction_number = self.unfunded_context.transaction_number();
2682+
let our_funding_satoshis = self.funding_negotiation_context
2683+
.our_funding_satoshis;
26042684

26052685
let mut output_index = None;
26062686
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
@@ -2627,7 +2707,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
26272707
};
26282708
self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint);
26292709

2630-
self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed");
2710+
self.context.assert_no_commitment_advancement(self.holder_commitment_transaction_number, "initial commitment_signed");
26312711
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
26322712
let commitment_signed = match commitment_signed {
26332713
Ok(commitment_signed) => commitment_signed,
@@ -2680,8 +2760,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
26802760
self.context.channel_state = channel_state;
26812761

26822762
// Clear the interactive transaction constructor
2683-
self.interactive_tx_constructor.take();
2684-
self.interactive_tx_signing_session = Some(signing_session);
2763+
*self.interactive_tx_constructor = None;
2764+
*self.interactive_tx_signing_session = Some(signing_session);
26852765

26862766
Ok((commitment_signed, funding_ready_for_sig_event))
26872767
}
@@ -5262,6 +5342,35 @@ impl<SP: Deref> FundedChannel<SP> where
52625342
SP::Target: SignerProvider,
52635343
<SP::Target as SignerProvider>::EcdsaSigner: EcdsaChannelSigner
52645344
{
5345+
/// If we are in splicing/refunding, return a short-lived [`NegotiatingV2ChannelView`].
5346+
#[cfg(splicing)]
5347+
fn as_renegotiating_channel(&mut self) -> Result<NegotiatingV2ChannelView<SP>, &'static str> {
5348+
if let Some(ref mut pending_splice) = &mut self.pending_splice {
5349+
if let Some(ref mut funding) = &mut pending_splice.funding_scope {
5350+
if
5351+
pending_splice.funding_negotiation_context.our_funding_satoshis != 0 ||
5352+
pending_splice.funding_negotiation_context.their_funding_satoshis.unwrap_or_default() != 0
5353+
{
5354+
Ok(NegotiatingV2ChannelView {
5355+
context: &mut self.context,
5356+
funding,
5357+
funding_negotiation_context: &mut pending_splice.funding_negotiation_context,
5358+
interactive_tx_constructor: &mut pending_splice.interactive_tx_constructor,
5359+
interactive_tx_signing_session: &mut pending_splice.interactive_tx_signing_session,
5360+
holder_commitment_transaction_number: self.holder_commitment_point.transaction_number(),
5361+
is_splice: true,
5362+
})
5363+
} else {
5364+
Err("Channel is not actively refunding")
5365+
}
5366+
} else {
5367+
Err("Channel is not refunding")
5368+
}
5369+
} else {
5370+
Err("Channel is not splice pending")
5371+
}
5372+
}
5373+
52655374
fn check_remote_fee<F: Deref, L: Deref>(
52665375
channel_type: &ChannelTypeFeatures, fee_estimator: &LowerBoundedFeeEstimator<F>,
52675376
feerate_per_kw: u32, cur_feerate_per_kw: Option<u32>, logger: &L
@@ -8895,10 +9004,11 @@ impl<SP: Deref> FundedChannel<SP> where
88959004
) -> Result<msgs::SpliceInit, APIError> {
88969005
// Check if a splice has been initiated already.
88979006
// Note: only a single outstanding splice is supported (per spec)
8898-
if let Some(splice_info) = &self.pending_splice {
9007+
if let Some(pending_splice) = &self.pending_splice {
88999008
return Err(APIError::APIMisuseError { err: format!(
89009009
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
8901-
self.context.channel_id(), splice_info.our_funding_contribution
9010+
self.context.channel_id(),
9011+
pending_splice.our_funding_contribution,
89029012
)});
89039013
}
89049014

@@ -8930,9 +9040,27 @@ impl<SP: Deref> FundedChannel<SP> where
89309040
"Insufficient inputs for splicing; channel ID {}, err {}",
89319041
self.context.channel_id(), err,
89329042
)})?;
9043+
// Convert inputs
9044+
let mut funding_inputs = Vec::new();
9045+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
9046+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(|_e| APIError::APIMisuseError { err: format!("Too large transaction")})?;
9047+
funding_inputs.push((tx_in.clone(), tx16));
9048+
}
89339049

9050+
let funding_negotiation_context = FundingNegotiationContext {
9051+
our_funding_satoshis: 0, // set at later phase
9052+
their_funding_satoshis: None, // set at later phase
9053+
funding_tx_locktime: LockTime::from_consensus(locktime),
9054+
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
9055+
our_funding_inputs: funding_inputs,
9056+
};
89349057
self.pending_splice = Some(PendingSplice {
89359058
our_funding_contribution: our_funding_contribution_satoshis,
9059+
awaiting_splice_ack: true, // we await splice_ack
9060+
funding_scope: None,
9061+
funding_negotiation_context,
9062+
interactive_tx_constructor: None,
9063+
interactive_tx_signing_session: None,
89369064
});
89379065

89389066
let msg = self.get_splice_init(our_funding_contribution_satoshis, funding_feerate_per_kw, locktime);
@@ -8965,9 +9093,11 @@ impl<SP: Deref> FundedChannel<SP> where
89659093
let our_funding_contribution_satoshis = 0i64;
89669094

89679095
// Check if a splice has been initiated already.
8968-
if let Some(splice_info) = &self.pending_splice {
9096+
if let Some(pending_splice) = &self.pending_splice {
89699097
return Err(ChannelError::Warn(format!(
8970-
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
9098+
"Channel {} has already a splice pending, contribution {}",
9099+
self.context.channel_id(),
9100+
pending_splice.our_funding_contribution,
89719101
)));
89729102
}
89739103

@@ -10648,6 +10778,19 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
1064810778
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
1064910779
self.generate_accept_channel_v2_message()
1065010780
}
10781+
10782+
/// Return a short-lived [`NegotiatingV2ChannelView`].
10783+
fn as_negotiating_channel(&mut self) -> NegotiatingV2ChannelView<SP> {
10784+
NegotiatingV2ChannelView {
10785+
context: &mut self.context,
10786+
funding: &mut self.funding,
10787+
funding_negotiation_context: &mut self.funding_negotiation_context,
10788+
interactive_tx_constructor: &mut self.interactive_tx_constructor,
10789+
interactive_tx_signing_session: &mut self.interactive_tx_signing_session,
10790+
holder_commitment_transaction_number: self.unfunded_context.transaction_number(),
10791+
is_splice: false,
10792+
}
10793+
}
1065110794
}
1065210795

1065310796
// Unfunded channel utilities

0 commit comments

Comments
 (0)