Skip to content

Commit 9c66f77

Browse files
committed
Rework ChannelManager::funding_transaction_signed
Previously, we'd emit a FundingTransactionReadyForSigning event once the initial commitment_signed is exchanged for a splicing/dual-funding attempt and require users to call back with their signed inputs using ChannelManager::funding_transaction_signed. While this approach worked in practice, it prevents us from abandoning a splice if we cannot or no longer wish to sign as the splice has already been committed to by this point. This commit reworks the API such that this is now possible. After exchanging tx_complete, we will no longer immediately send our initial commitment_signed. We will now emit the FundingTransactionReadyForSigning event and wait for the user to call back before releasing both our initial commitment_signed and our tx_signatures. As a result, the event is now persisted, as there is only one possible path in which it is generated. Note that we continue to only emit the event if a local contribution to negotiated transaction was made. Future work will expose a cancellation API such that we can abandon splice attempts safely (we can just force close the channel with dual-funding).
1 parent 8cdc86a commit 9c66f77

File tree

6 files changed

+365
-374
lines changed

6 files changed

+365
-374
lines changed

lightning/src/ln/channel.rs

Lines changed: 121 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,10 +1904,7 @@ where
19041904

19051905
pub fn tx_complete<L: Deref>(
19061906
&mut self, msg: &msgs::TxComplete, logger: &L,
1907-
) -> Result<
1908-
(Option<InteractiveTxMessageSend>, Option<msgs::CommitmentSigned>),
1909-
(ChannelError, Option<SpliceFundingFailed>),
1910-
>
1907+
) -> Result<TxCompleteResult, (ChannelError, Option<SpliceFundingFailed>)>
19111908
where
19121909
L::Target: Logger,
19131910
{
@@ -1934,13 +1931,38 @@ where
19341931
let funding_outpoint = if let Some(funding_outpoint) = negotiation_complete {
19351932
funding_outpoint
19361933
} else {
1937-
return Ok((interactive_tx_msg_send, None));
1934+
return Ok(TxCompleteResult {
1935+
interactive_tx_msg_send,
1936+
event_unsigned_tx: None,
1937+
funding_tx_signed: None,
1938+
});
19381939
};
19391940

1940-
let commitment_signed = self
1941-
.funding_tx_constructed(funding_outpoint, logger)
1941+
self.funding_tx_constructed(funding_outpoint)
19421942
.map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?;
1943-
Ok((interactive_tx_msg_send, Some(commitment_signed)))
1943+
1944+
let signing_session = self
1945+
.context()
1946+
.interactive_tx_signing_session
1947+
.as_ref()
1948+
.expect("The signing session must have been initialized in funding_tx_constructed");
1949+
let has_local_contribution = signing_session.has_local_contribution();
1950+
1951+
let event_unsigned_tx =
1952+
has_local_contribution.then(|| signing_session.unsigned_tx().tx().clone());
1953+
1954+
let funding_tx_signed = if !has_local_contribution {
1955+
let funding_txid = signing_session.unsigned_tx().tx().compute_txid();
1956+
if let ChannelPhase::Funded(chan) = &mut self.phase {
1957+
chan.funding_transaction_signed(funding_txid, vec![], 0, logger).ok()
1958+
} else {
1959+
None
1960+
}
1961+
} else {
1962+
None
1963+
};
1964+
1965+
Ok(TxCompleteResult { interactive_tx_msg_send, event_unsigned_tx, funding_tx_signed })
19441966
}
19451967

19461968
pub fn tx_abort<L: Deref>(
@@ -2046,14 +2068,8 @@ where
20462068
result.map(|monitor| (self.as_funded_mut().expect("Channel should be funded"), monitor))
20472069
}
20482070

2049-
fn funding_tx_constructed<L: Deref>(
2050-
&mut self, funding_outpoint: OutPoint, logger: &L,
2051-
) -> Result<msgs::CommitmentSigned, AbortReason>
2052-
where
2053-
L::Target: Logger,
2054-
{
2055-
let logger = WithChannelContext::from(logger, self.context(), None);
2056-
let (interactive_tx_constructor, commitment_signed) = match &mut self.phase {
2071+
fn funding_tx_constructed(&mut self, funding_outpoint: OutPoint) -> Result<(), AbortReason> {
2072+
let interactive_tx_constructor = match &mut self.phase {
20572073
ChannelPhase::UnfundedV2(chan) => {
20582074
debug_assert_eq!(
20592075
chan.context.channel_state,
@@ -2072,77 +2088,31 @@ where
20722088
chan.funding.channel_transaction_parameters.funding_outpoint =
20732089
Some(funding_outpoint);
20742090

2075-
let interactive_tx_constructor = chan
2076-
.interactive_tx_constructor
2091+
chan.interactive_tx_constructor
20772092
.take()
2078-
.expect("PendingV2Channel::interactive_tx_constructor should be set");
2079-
2080-
let commitment_signed =
2081-
chan.context.get_initial_commitment_signed_v2(&chan.funding, &&logger);
2082-
let commitment_signed = match commitment_signed {
2083-
Some(commitment_signed) => commitment_signed,
2084-
// TODO(dual_funding): Support async signing
2085-
None => {
2086-
return Err(AbortReason::InternalError(
2087-
"Failed to compute commitment_signed signatures",
2088-
));
2089-
},
2090-
};
2091-
2092-
(interactive_tx_constructor, commitment_signed)
2093+
.expect("PendingV2Channel::interactive_tx_constructor should be set")
20932094
},
20942095
ChannelPhase::Funded(chan) => {
20952096
if let Some(pending_splice) = chan.pending_splice.as_mut() {
2096-
pending_splice
2097-
.funding_negotiation
2098-
.take()
2099-
.and_then(|funding_negotiation| {
2100-
if let FundingNegotiation::ConstructingTransaction {
2101-
funding,
2102-
interactive_tx_constructor,
2103-
} = funding_negotiation
2104-
{
2105-
let is_initiator = interactive_tx_constructor.is_initiator();
2106-
Some((is_initiator, funding, interactive_tx_constructor))
2107-
} else {
2108-
// Replace the taken state for later error handling
2109-
pending_splice.funding_negotiation = Some(funding_negotiation);
2110-
None
2111-
}
2112-
})
2113-
.ok_or_else(|| {
2114-
AbortReason::InternalError(
2115-
"Got a tx_complete message in an invalid state",
2116-
)
2117-
})
2118-
.and_then(|(is_initiator, mut funding, interactive_tx_constructor)| {
2119-
funding.channel_transaction_parameters.funding_outpoint =
2120-
Some(funding_outpoint);
2121-
match chan.context.get_initial_commitment_signed_v2(&funding, &&logger)
2122-
{
2123-
Some(commitment_signed) => {
2124-
// Advance the state
2125-
pending_splice.funding_negotiation =
2126-
Some(FundingNegotiation::AwaitingSignatures {
2127-
is_initiator,
2128-
funding,
2129-
});
2130-
Ok((interactive_tx_constructor, commitment_signed))
2131-
},
2132-
// TODO(splicing): Support async signing
2133-
None => {
2134-
// Restore the taken state for later error handling
2135-
pending_splice.funding_negotiation =
2136-
Some(FundingNegotiation::ConstructingTransaction {
2137-
funding,
2138-
interactive_tx_constructor,
2139-
});
2140-
Err(AbortReason::InternalError(
2141-
"Failed to compute commitment_signed signatures",
2142-
))
2143-
},
2144-
}
2145-
})?
2097+
let funding_negotiation = pending_splice.funding_negotiation.take();
2098+
if let Some(FundingNegotiation::ConstructingTransaction {
2099+
mut funding,
2100+
interactive_tx_constructor,
2101+
}) = funding_negotiation
2102+
{
2103+
let is_initiator = interactive_tx_constructor.is_initiator();
2104+
funding.channel_transaction_parameters.funding_outpoint =
2105+
Some(funding_outpoint);
2106+
pending_splice.funding_negotiation =
2107+
Some(FundingNegotiation::AwaitingSignatures { is_initiator, funding });
2108+
interactive_tx_constructor
2109+
} else {
2110+
// Replace the taken state for later error handling
2111+
pending_splice.funding_negotiation = funding_negotiation;
2112+
return Err(AbortReason::InternalError(
2113+
"Got a tx_complete message in an invalid state",
2114+
));
2115+
}
21462116
} else {
21472117
return Err(AbortReason::InternalError(
21482118
"Got a tx_complete message in an invalid state",
@@ -2159,7 +2129,7 @@ where
21592129

21602130
let signing_session = interactive_tx_constructor.into_signing_session();
21612131
self.context_mut().interactive_tx_signing_session = Some(signing_session);
2162-
Ok(commitment_signed)
2132+
Ok(())
21632133
}
21642134

21652135
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
@@ -2911,6 +2881,7 @@ where
29112881
/// send it first.
29122882
resend_order: RAACommitmentOrder,
29132883

2884+
monitor_pending_tx_signatures: bool,
29142885
monitor_pending_channel_ready: bool,
29152886
monitor_pending_revoke_and_ack: bool,
29162887
monitor_pending_commitment_signed: bool,
@@ -3642,6 +3613,7 @@ where
36423613

36433614
resend_order: RAACommitmentOrder::CommitmentFirst,
36443615

3616+
monitor_pending_tx_signatures: false,
36453617
monitor_pending_channel_ready: false,
36463618
monitor_pending_revoke_and_ack: false,
36473619
monitor_pending_commitment_signed: false,
@@ -3881,6 +3853,7 @@ where
38813853

38823854
resend_order: RAACommitmentOrder::CommitmentFirst,
38833855

3856+
monitor_pending_tx_signatures: false,
38843857
monitor_pending_channel_ready: false,
38853858
monitor_pending_revoke_and_ack: false,
38863859
monitor_pending_commitment_signed: false,
@@ -6860,8 +6833,25 @@ type BestBlockUpdatedRes = (
68606833
Option<msgs::AnnouncementSignatures>,
68616834
);
68626835

6836+
/// The result of handling a `tx_complete` message during interactive transaction construction.
6837+
pub(crate) struct TxCompleteResult {
6838+
/// The message to send to the counterparty, if any.
6839+
pub interactive_tx_msg_send: Option<InteractiveTxMessageSend>,
6840+
6841+
/// If the negotiation completed and the holder has local contributions, this contains the
6842+
/// unsigned funding transaction for the `FundingTransactionReadyForSigning` event.
6843+
pub event_unsigned_tx: Option<Transaction>,
6844+
6845+
/// If the negotiation completed and the holder has no local contributions, this contains
6846+
/// the result of automatically calling `funding_transaction_signed` with empty witnesses.
6847+
pub funding_tx_signed: Option<FundingTxSigned>,
6848+
}
6849+
68636850
/// The result of signing a funding transaction negotiated using the interactive-tx protocol.
68646851
pub struct FundingTxSigned {
6852+
/// The initial `commitment_signed` message to send to the counterparty, if necessary.
6853+
pub commitment_signed: Option<msgs::CommitmentSigned>,
6854+
68656855
/// Signatures that should be sent to the counterparty, if necessary.
68666856
pub tx_signatures: Option<msgs::TxSignatures>,
68676857

@@ -8051,6 +8041,7 @@ where
80518041
Vec::new(),
80528042
logger,
80538043
);
8044+
self.context.monitor_pending_tx_signatures = true;
80548045

80558046
Ok(self.push_ret_blockable_mon_update(monitor_update))
80568047
}
@@ -9104,6 +9095,7 @@ where
91049095
// Our `tx_signatures` either should've been the first time we processed them,
91059096
// or we're waiting for our counterparty to send theirs first.
91069097
return Ok(FundingTxSigned {
9098+
commitment_signed: None,
91079099
tx_signatures: None,
91089100
funding_tx: None,
91099101
splice_negotiated: None,
@@ -9117,6 +9109,7 @@ where
91179109
// We may be handling a duplicate call and the funding was already locked so we
91189110
// no longer have the signing session present.
91199111
return Ok(FundingTxSigned {
9112+
commitment_signed: None,
91209113
tx_signatures: None,
91219114
funding_tx: None,
91229115
splice_negotiated: None,
@@ -9178,7 +9171,21 @@ where
91789171
(None, None)
91799172
};
91809173

9181-
Ok(FundingTxSigned { tx_signatures, funding_tx, splice_negotiated, splice_locked })
9174+
let funding = self
9175+
.pending_splice
9176+
.as_ref()
9177+
.and_then(|pending_splice| pending_splice.funding_negotiation.as_ref())
9178+
.and_then(|funding_negotiation| funding_negotiation.as_funding())
9179+
.unwrap_or(&self.funding);
9180+
let commitment_signed = self.context.get_initial_commitment_signed_v2(funding, &&logger);
9181+
9182+
Ok(FundingTxSigned {
9183+
commitment_signed,
9184+
tx_signatures,
9185+
funding_tx,
9186+
splice_negotiated,
9187+
splice_locked,
9188+
})
91829189
}
91839190

91849191
pub fn tx_signatures<L: Deref>(
@@ -9246,6 +9253,7 @@ where
92469253
};
92479254

92489255
Ok(FundingTxSigned {
9256+
commitment_signed: None,
92499257
tx_signatures: holder_tx_signatures,
92509258
funding_tx,
92519259
splice_negotiated,
@@ -9451,6 +9459,25 @@ where
94519459
self.context.channel_state.clear_monitor_update_in_progress();
94529460
assert_eq!(self.blocked_monitor_updates_pending(), 0);
94539461

9462+
let mut tx_signatures = self
9463+
.context
9464+
.monitor_pending_tx_signatures
9465+
.then(|| ())
9466+
.and_then(|_| self.context.interactive_tx_signing_session.as_ref())
9467+
.and_then(|signing_session| signing_session.holder_tx_signatures().clone());
9468+
if tx_signatures.is_some() {
9469+
// We want to clear that the monitor update for our `tx_signatures` has completed, but
9470+
// we may still need to hold back the message until it's ready to be sent.
9471+
self.context.monitor_pending_tx_signatures = false;
9472+
let signing_session = self.context.interactive_tx_signing_session.as_ref()
9473+
.expect("We have a tx_signatures message so we must have a valid signing session");
9474+
if !signing_session.holder_sends_tx_signatures_first()
9475+
&& !signing_session.has_received_tx_signatures()
9476+
{
9477+
tx_signatures.take();
9478+
}
9479+
}
9480+
94549481
// If we're past (or at) the AwaitingChannelReady stage on an outbound (or V2-established) channel,
94559482
// try to (re-)broadcast the funding transaction as we may have declined to broadcast it when we
94569483
// first received the funding_signed.
@@ -9539,7 +9566,7 @@ where
95399566
match commitment_order { RAACommitmentOrder::CommitmentFirst => "commitment", RAACommitmentOrder::RevokeAndACKFirst => "RAA"});
95409567
MonitorRestoreUpdates {
95419568
raa, commitment_update, commitment_order, accepted_htlcs, failed_htlcs, finalized_claimed_htlcs,
9542-
pending_update_adds, funding_broadcastable, channel_ready, announcement_sigs, tx_signatures: None,
9569+
pending_update_adds, funding_broadcastable, channel_ready, announcement_sigs, tx_signatures,
95439570
channel_ready_order,
95449571
}
95459572
}
@@ -15074,6 +15101,9 @@ where
1507415101
let pending_splice =
1507515102
self.pending_splice.as_ref().filter(|_| !self.should_reset_pending_splice_state(false));
1507615103

15104+
let monitor_pending_tx_signatures =
15105+
self.context.monitor_pending_tx_signatures.then_some(());
15106+
1507715107
write_tlv_fields!(writer, {
1507815108
(0, self.context.announcement_sigs, option),
1507915109
// minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
@@ -15093,6 +15123,7 @@ where
1509315123
(9, self.context.target_closing_feerate_sats_per_kw, option),
1509415124
(10, monitor_pending_update_adds, option), // Added in 0.0.122
1509515125
(11, self.context.monitor_pending_finalized_fulfills, required_vec),
15126+
(12, monitor_pending_tx_signatures, option), // Added in 0.3
1509615127
(13, self.context.channel_creation_height, required),
1509715128
(15, preimages, required_vec),
1509815129
(17, self.context.announcement_sigs_state, required),
@@ -15524,6 +15555,8 @@ where
1552415555
let mut holding_cell_accountable: Option<Vec<bool>> = None;
1552515556
let mut pending_outbound_accountable: Option<Vec<bool>> = None;
1552615557

15558+
let mut monitor_pending_tx_signatures: Option<()> = None;
15559+
1552715560
read_tlv_fields!(reader, {
1552815561
(0, announcement_sigs, option),
1552915562
(1, minimum_depth, option),
@@ -15537,6 +15570,7 @@ where
1553715570
(9, target_closing_feerate_sats_per_kw, option),
1553815571
(10, monitor_pending_update_adds, option), // Added in 0.0.122
1553915572
(11, monitor_pending_finalized_fulfills, optional_vec),
15573+
(12, monitor_pending_tx_signatures, option), // Added in 0.3
1554015574
(13, channel_creation_height, required),
1554115575
(15, preimages, required_vec), // The preimages transitioned from optional to required in 0.2
1554215576
(17, announcement_sigs_state, required),
@@ -15949,6 +15983,7 @@ where
1594915983

1595015984
resend_order,
1595115985

15986+
monitor_pending_tx_signatures: monitor_pending_tx_signatures.is_some(),
1595215987
monitor_pending_channel_ready,
1595315988
monitor_pending_revoke_and_ack,
1595415989
monitor_pending_commitment_signed,

0 commit comments

Comments
 (0)