Skip to content

Commit 7b96c69

Browse files
committed
Handle receiving channel_reestablish with next_funding_txid
This follows the the specification closely in branching without being too verbose, so that it should be easy to follow the logic. See: https://github.com/lightning/bolts/blob/aa5207a/02-peer-protocol.md?plain=1#L2520-L2531
1 parent 40baf3e commit 7b96c69

File tree

3 files changed

+123
-17
lines changed

3 files changed

+123
-17
lines changed

lightning/src/ln/channel.rs

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,8 @@ pub(super) struct ReestablishResponses {
972972
pub order: RAACommitmentOrder,
973973
pub announcement_sigs: Option<msgs::AnnouncementSignatures>,
974974
pub shutdown_msg: Option<msgs::Shutdown>,
975+
pub tx_signatures: Option<msgs::TxSignatures>,
976+
pub tx_abort: Option<msgs::TxAbort>,
975977
}
976978

977979
/// The first message we send to our peer after connection
@@ -2280,7 +2282,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22802282

22812283
let mut output_index = None;
22822284
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
2283-
for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() {
2285+
for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() {
22842286
if outp.script_pubkey() == &expected_spk && outp.value() == self.funding.get_value_satoshis() {
22852287
if output_index.is_some() {
22862288
return Err(ChannelError::Close(
@@ -2293,7 +2295,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22932295
}
22942296
}
22952297
let outpoint = if let Some(output_index) = output_index {
2296-
OutPoint { txid: signing_session.unsigned_tx.compute_txid(), index: output_index }
2298+
OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
22972299
} else {
22982300
return Err(ChannelError::Close(
22992301
(
@@ -2307,7 +2309,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
23072309
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
23082310
let commitment_signed = match commitment_signed {
23092311
Ok(commitment_signed) => {
2310-
self.funding.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
2312+
self.funding.funding_transaction = Some(signing_session.unsigned_tx().build_unsigned_tx());
23112313
commitment_signed
23122314
},
23132315
Err(err) => {
@@ -6232,7 +6234,7 @@ impl<SP: Deref> FundedChannel<SP> where
62326234
}
62336235

62346236
if let Some(ref mut signing_session) = self.interactive_tx_signing_session {
6235-
if msg.tx_hash != signing_session.unsigned_tx.compute_txid() {
6237+
if msg.tx_hash != signing_session.unsigned_tx().compute_txid() {
62366238
return Err(ChannelError::Close(
62376239
(
62386240
"The txid for the transaction does not match".to_string(),
@@ -6880,7 +6882,10 @@ impl<SP: Deref> FundedChannel<SP> where
68806882
}
68816883

68826884
if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
6883-
msg.next_local_commitment_number == 0 {
6885+
(msg.next_local_commitment_number == 0 && msg.next_funding_txid.is_none()) {
6886+
// Note: This also covers the following case in the V2 channel establishment specification:
6887+
// if `next_funding_txid` is not set, and `next_commitment_number` is zero:
6888+
// MUST immediately fail the channel and broadcast any relevant latest commitment transaction.
68846889
return Err(ChannelError::close("Peer sent an invalid channel_reestablish to force close in a non-standard way".to_owned()));
68856890
}
68866891

@@ -6944,6 +6949,8 @@ impl<SP: Deref> FundedChannel<SP> where
69446949
raa: None, commitment_update: None,
69456950
order: RAACommitmentOrder::CommitmentFirst,
69466951
shutdown_msg, announcement_sigs,
6952+
tx_signatures: None,
6953+
tx_abort: None,
69476954
});
69486955
}
69496956

@@ -6953,6 +6960,8 @@ impl<SP: Deref> FundedChannel<SP> where
69536960
raa: None, commitment_update: None,
69546961
order: RAACommitmentOrder::CommitmentFirst,
69556962
shutdown_msg, announcement_sigs,
6963+
tx_signatures: None,
6964+
tx_abort: None,
69566965
});
69576966
}
69586967

@@ -6995,11 +7004,76 @@ impl<SP: Deref> FundedChannel<SP> where
69957004
log_debug!(logger, "Reconnected channel {} with no loss", &self.context.channel_id());
69967005
}
69977006

7007+
// if next_funding_txid is set:
7008+
let (commitment_update, tx_signatures, tx_abort) = if let Some(next_funding_txid) = msg.next_funding_txid {
7009+
if let Some(session) = &self.interactive_tx_signing_session {
7010+
// if next_funding_txid matches the latest interactive funding transaction:
7011+
if session.unsigned_tx().compute_txid() == next_funding_txid {
7012+
debug_assert_eq!(session.unsigned_tx().compute_txid(), self.maybe_get_next_funding_txid().unwrap());
7013+
7014+
let commitment_update = if !session.counterparty_sent_tx_signatures() && msg.next_local_commitment_number == 0 {
7015+
// if it has not received tx_signatures for that funding transaction AND
7016+
// if next_commitment_number is zero:
7017+
// MUST retransmit its commitment_signed for that funding transaction.
7018+
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger)?;
7019+
Some(msgs::CommitmentUpdate {
7020+
commitment_signed,
7021+
update_add_htlcs: vec![],
7022+
update_fulfill_htlcs: vec![],
7023+
update_fail_htlcs: vec![],
7024+
update_fail_malformed_htlcs: vec![],
7025+
update_fee: None,
7026+
})
7027+
} else { None };
7028+
// if it has not received tx_signatures for that funding transaction AND
7029+
// if it has already received commitment_signed AND it should sign first, as specified in the tx_signatures requirements:
7030+
// MUST send its tx_signatures for that funding transaction.
7031+
// else if it HAS received commitment_signed AND has received tx_signatures for that funding transaction:
7032+
// MUST send its tx_signatures for that funding transaction.
7033+
let tx_signatures = if session.has_received_commitment_signed() && ((
7034+
!session.counterparty_sent_tx_signatures() &&
7035+
session.holder_sends_tx_signatures_first()
7036+
) || session.counterparty_sent_tx_signatures()) {
7037+
// This should have already been set in `commitment_signed_initial_v2`, but check again
7038+
// just in case.
7039+
if self.context.channel_state.is_monitor_update_in_progress() {
7040+
log_debug!(logger, "Not sending tx_signatures: a monitor update is in progress. Setting monitor_pending_tx_signatures.");
7041+
if self.context.monitor_pending_tx_signatures.is_none() {
7042+
self.context.monitor_pending_tx_signatures = session.holder_tx_signatures().clone();
7043+
}
7044+
None
7045+
} else {
7046+
// If `holder_tx_signatures` is `None` here, the `tx_signatures` message will be sent
7047+
// when the holder provides their witnesses as this will queue a `tx_signatures` if the
7048+
// holder must send one.
7049+
session.holder_tx_signatures().clone()
7050+
}
7051+
} else {
7052+
if !session.has_received_commitment_signed() {
7053+
self.context.expecting_peer_commitment_signed = true;
7054+
}
7055+
None
7056+
};
7057+
(commitment_update, tx_signatures, None)
7058+
} else {
7059+
// MUST send tx_abort to let the sending node know that they can forget this funding transaction.
7060+
(None, None, Some(msgs::TxAbort { channel_id: self.context.channel_id(), data: vec![] }))
7061+
}
7062+
} else {
7063+
return Err(ChannelError::close("Counterparty set `next_funding_txid` at incorrect state".into()));
7064+
}
7065+
} else {
7066+
// Don't send anything related to interactive signing if `next_funding_txid` is not set.
7067+
(None, None, None)
7068+
};
7069+
69987070
Ok(ReestablishResponses {
69997071
channel_ready, shutdown_msg, announcement_sigs,
70007072
raa: required_revoke,
7001-
commitment_update: None,
7073+
commitment_update,
70027074
order: self.context.resend_order.clone(),
7075+
tx_signatures,
7076+
tx_abort,
70037077
})
70047078
} else if msg.next_local_commitment_number == next_counterparty_commitment_number - 1 {
70057079
if required_revoke.is_some() || self.context.signer_pending_revoke_and_ack {
@@ -7014,6 +7088,8 @@ impl<SP: Deref> FundedChannel<SP> where
70147088
channel_ready, shutdown_msg, announcement_sigs,
70157089
commitment_update: None, raa: None,
70167090
order: self.context.resend_order.clone(),
7091+
tx_signatures: None,
7092+
tx_abort: None,
70177093
})
70187094
} else {
70197095
let commitment_update = if self.context.resend_order == RAACommitmentOrder::RevokeAndACKFirst
@@ -7036,6 +7112,8 @@ impl<SP: Deref> FundedChannel<SP> where
70367112
channel_ready, shutdown_msg, announcement_sigs,
70377113
raa, commitment_update,
70387114
order: self.context.resend_order.clone(),
7115+
tx_signatures: None,
7116+
tx_abort: None,
70397117
})
70407118
}
70417119
} else if msg.next_local_commitment_number < next_counterparty_commitment_number {
@@ -8329,7 +8407,7 @@ impl<SP: Deref> FundedChannel<SP> where
83298407
// to the txid of that interactive transaction, else we MUST NOT set it.
83308408
if let Some(signing_session) = &self.interactive_tx_signing_session {
83318409
// Since we have a signing_session, this implies we've sent an initial `commitment_signed`...
8332-
if !signing_session.counterparty_sent_tx_signatures {
8410+
if !signing_session.counterparty_sent_tx_signatures() {
83338411
// ...but we didn't receive a `tx_signatures` from the counterparty yet.
83348412
Some(self.funding_outpoint().txid)
83358413
} else {

lightning/src/ln/channelmanager.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3225,7 +3225,7 @@ macro_rules! handle_monitor_update_completion {
32253225
&mut $peer_state.pending_msg_events, $chan, updates.raa,
32263226
updates.commitment_update, updates.order, updates.accepted_htlcs, updates.pending_update_adds,
32273227
updates.funding_broadcastable, updates.channel_ready,
3228-
updates.announcement_sigs, updates.tx_signatures);
3228+
updates.announcement_sigs, updates.tx_signatures, None);
32293229
if let Some(upd) = channel_update {
32303230
$peer_state.pending_msg_events.push(upd);
32313231
}
@@ -7663,10 +7663,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
76637663
pending_forwards: Vec<(PendingHTLCInfo, u64)>, pending_update_adds: Vec<msgs::UpdateAddHTLC>,
76647664
funding_broadcastable: Option<Transaction>,
76657665
channel_ready: Option<msgs::ChannelReady>, announcement_sigs: Option<msgs::AnnouncementSignatures>,
7666-
tx_signatures: Option<msgs::TxSignatures>
7666+
tx_signatures: Option<msgs::TxSignatures>, tx_abort: Option<msgs::TxAbort>,
76677667
) -> (Option<(u64, Option<PublicKey>, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)>, Option<(u64, Vec<msgs::UpdateAddHTLC>)>) {
76687668
let logger = WithChannelContext::from(&self.logger, &channel.context, None);
7669-
log_trace!(logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {} pending update_add_htlcs, {}broadcasting funding, {} channel ready, {} announcement, {} tx_signatures",
7669+
log_trace!(logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {} pending update_add_htlcs, {}broadcasting funding, {} channel ready, {} announcement, {} tx_signatures, {} tx_abort",
76707670
&channel.context.channel_id(),
76717671
if raa.is_some() { "an" } else { "no" },
76727672
if commitment_update.is_some() { "a" } else { "no" },
@@ -7675,6 +7675,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
76757675
if channel_ready.is_some() { "sending" } else { "without" },
76767676
if announcement_sigs.is_some() { "sending" } else { "without" },
76777677
if tx_signatures.is_some() { "sending" } else { "without" },
7678+
if tx_abort.is_some() { "sending" } else { "without" },
76787679
);
76797680

76807681
let counterparty_node_id = channel.context.get_counterparty_node_id();
@@ -7708,6 +7709,12 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
77087709
msg,
77097710
});
77107711
}
7712+
if let Some(msg) = tx_abort {
7713+
pending_msg_events.push(MessageSendEvent::SendTxAbort {
7714+
node_id: counterparty_node_id,
7715+
msg,
7716+
});
7717+
}
77117718

77127719
macro_rules! handle_cs { () => {
77137720
if let Some(update) = commitment_update {
@@ -9456,7 +9463,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
94569463
let need_lnd_workaround = chan.context.workaround_lnd_bug_4006.take();
94579464
let (htlc_forwards, decode_update_add_htlcs) = self.handle_channel_resumption(
94589465
&mut peer_state.pending_msg_events, chan, responses.raa, responses.commitment_update, responses.order,
9459-
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs, None);
9466+
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs,
9467+
responses.tx_signatures, responses.tx_abort);
94609468
debug_assert!(htlc_forwards.is_none());
94619469
debug_assert!(decode_update_add_htlcs.is_none());
94629470
if let Some(upd) = channel_update {

lightning/src/ln/interactivetxs.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,16 +288,36 @@ impl ConstructedTransaction {
288288
/// https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#sharing-funding-signatures-tx_signatures
289289
#[derive(Debug, Clone, PartialEq)]
290290
pub(crate) struct InteractiveTxSigningSession {
291-
pub unsigned_tx: ConstructedTransaction,
292-
pub counterparty_sent_tx_signatures: bool,
291+
unsigned_tx: ConstructedTransaction,
292+
counterparty_sent_tx_signatures: bool,
293293
holder_sends_tx_signatures_first: bool,
294-
received_commitment_signed: bool,
294+
has_received_commitment_signed: bool,
295295
holder_tx_signatures: Option<TxSignatures>,
296296
}
297297

298298
impl InteractiveTxSigningSession {
299+
pub fn unsigned_tx(&self) -> &ConstructedTransaction {
300+
&self.unsigned_tx
301+
}
302+
303+
pub fn counterparty_sent_tx_signatures(&self) -> bool {
304+
self.counterparty_sent_tx_signatures
305+
}
306+
307+
pub fn holder_sends_tx_signatures_first(&self) -> bool {
308+
self.holder_sends_tx_signatures_first
309+
}
310+
311+
pub fn has_received_commitment_signed(&self) -> bool {
312+
self.has_received_commitment_signed
313+
}
314+
315+
pub fn holder_tx_signatures(&self) -> &Option<TxSignatures> {
316+
&self.holder_tx_signatures
317+
}
318+
299319
pub fn received_commitment_signed(&mut self) -> Option<TxSignatures> {
300-
self.received_commitment_signed = true;
320+
self.has_received_commitment_signed = true;
301321
if self.holder_sends_tx_signatures_first {
302322
self.holder_tx_signatures.clone()
303323
} else {
@@ -306,7 +326,7 @@ impl InteractiveTxSigningSession {
306326
}
307327

308328
pub fn get_tx_signatures(&self) -> Option<TxSignatures> {
309-
if self.received_commitment_signed {
329+
if self.has_received_commitment_signed {
310330
self.holder_tx_signatures.clone()
311331
} else {
312332
None
@@ -987,7 +1007,7 @@ macro_rules! define_state_transitions {
9871007
let signing_session = InteractiveTxSigningSession {
9881008
holder_sends_tx_signatures_first: tx.holder_sends_tx_signatures_first,
9891009
unsigned_tx: tx,
990-
received_commitment_signed: false,
1010+
has_received_commitment_signed: false,
9911011
holder_tx_signatures: None,
9921012
counterparty_sent_tx_signatures: false,
9931013
};

0 commit comments

Comments
 (0)