Skip to content

Commit 2079148

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 4d9cfd8 commit 2079148

File tree

3 files changed

+109
-17
lines changed

3 files changed

+109
-17
lines changed

Diff for: lightning/src/ln/channel.rs

+71-7
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,8 @@ pub(super) struct ReestablishResponses {
967967
pub order: RAACommitmentOrder,
968968
pub announcement_sigs: Option<msgs::AnnouncementSignatures>,
969969
pub shutdown_msg: Option<msgs::Shutdown>,
970+
pub tx_signatures: Option<msgs::TxSignatures>,
971+
pub tx_abort: Option<msgs::TxAbort>,
970972
}
971973

972974
/// The first message we send to our peer after connection
@@ -2272,7 +2274,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22722274

22732275
let mut output_index = None;
22742276
let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh();
2275-
for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() {
2277+
for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() {
22762278
if outp.script_pubkey() == &expected_spk && outp.value() == self.funding.get_value_satoshis() {
22772279
if output_index.is_some() {
22782280
return Err(ChannelError::Close(
@@ -2285,7 +2287,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22852287
}
22862288
}
22872289
let outpoint = if let Some(output_index) = output_index {
2288-
OutPoint { txid: signing_session.unsigned_tx.compute_txid(), index: output_index }
2290+
OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
22892291
} else {
22902292
return Err(ChannelError::Close(
22912293
(
@@ -2299,7 +2301,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22992301
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger);
23002302
let commitment_signed = match commitment_signed {
23012303
Ok(commitment_signed) => {
2302-
self.funding.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
2304+
self.funding.funding_transaction = Some(signing_session.unsigned_tx().build_unsigned_tx());
23032305
commitment_signed
23042306
},
23052307
Err(err) => {
@@ -6159,7 +6161,7 @@ impl<SP: Deref> FundedChannel<SP> where
61596161
}
61606162

61616163
if let Some(ref mut signing_session) = self.interactive_tx_signing_session {
6162-
if msg.tx_hash != signing_session.unsigned_tx.compute_txid() {
6164+
if msg.tx_hash != signing_session.unsigned_tx().compute_txid() {
61636165
return Err(ChannelError::Close(
61646166
(
61656167
"The txid for the transaction does not match".to_string(),
@@ -6804,7 +6806,7 @@ impl<SP: Deref> FundedChannel<SP> where
68046806
}
68056807

68066808
if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
6807-
msg.next_local_commitment_number == 0 {
6809+
msg.next_local_commitment_number == 0 && msg.next_funding_txid.is_none() {
68086810
return Err(ChannelError::close("Peer sent an invalid channel_reestablish to force close in a non-standard way".to_owned()));
68096811
}
68106812

@@ -6868,6 +6870,8 @@ impl<SP: Deref> FundedChannel<SP> where
68686870
raa: None, commitment_update: None,
68696871
order: RAACommitmentOrder::CommitmentFirst,
68706872
shutdown_msg, announcement_sigs,
6873+
tx_signatures: None,
6874+
tx_abort: None,
68716875
});
68726876
}
68736877

@@ -6877,6 +6881,8 @@ impl<SP: Deref> FundedChannel<SP> where
68776881
raa: None, commitment_update: None,
68786882
order: RAACommitmentOrder::CommitmentFirst,
68796883
shutdown_msg, announcement_sigs,
6884+
tx_signatures: None,
6885+
tx_abort: None,
68806886
});
68816887
}
68826888

@@ -6919,11 +6925,65 @@ impl<SP: Deref> FundedChannel<SP> where
69196925
log_debug!(logger, "Reconnected channel {} with no loss", &self.context.channel_id());
69206926
}
69216927

6928+
// if next_funding_txid is set:
6929+
let (commitment_update, tx_signatures, tx_abort) = if let Some(next_funding_txid) = msg.next_funding_txid {
6930+
if let Some(session) = &self.interactive_tx_signing_session {
6931+
// if next_funding_txid matches the latest interactive funding transaction:
6932+
if session.unsigned_tx().compute_txid() == next_funding_txid {
6933+
// if it has not received tx_signatures for that funding transaction:
6934+
if !session.counterparty_sent_tx_signatures() {
6935+
// if next_commitment_number is zero:
6936+
let commitment_update = if msg.next_local_commitment_number == 0 {
6937+
// MUST retransmit its commitment_signed for that funding transaction.
6938+
let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger)?;
6939+
Some(msgs::CommitmentUpdate {
6940+
commitment_signed,
6941+
update_add_htlcs: vec![],
6942+
update_fulfill_htlcs: vec![],
6943+
update_fail_htlcs: vec![],
6944+
update_fail_malformed_htlcs: vec![],
6945+
update_fee: None,
6946+
})
6947+
} else { None };
6948+
// if it has already received commitment_signed and it should sign first, as specified in the tx_signatures requirements:
6949+
if session.has_received_commitment_signed() && session.holder_sends_tx_signatures_first() {
6950+
// MUST send its tx_signatures for that funding transaction.
6951+
(commitment_update, session.holder_tx_signatures().clone(), None)
6952+
} else {
6953+
(commitment_update, None, None)
6954+
}
6955+
} else {
6956+
// if it has already received tx_signatures for that funding transaction:
6957+
// MUST send its tx_signatures for that funding transaction.
6958+
(None, session.holder_tx_signatures().clone(), None)
6959+
}
6960+
} else {
6961+
// MUST send tx_abort to let the sending node know that they can forget this funding transaction.
6962+
(None, None, Some(msgs::TxAbort { channel_id: self.context.channel_id(), data: vec![] }))
6963+
}
6964+
} else {
6965+
return Err(ChannelError::close("Counterparty set `next_funding_txid` at incorrect state".into()));
6966+
}
6967+
} else {
6968+
// if `next_funding_txid` is not set, and `next_commitment_number` is zero:
6969+
if msg.next_local_commitment_number == 0 {
6970+
// MUST immediately fail the channel and broadcast any relevant latest commitment transaction.
6971+
return Err(ChannelError::close(format!(
6972+
"Peer attempted to reestablish channel expecting a future local commitment transaction: {} (received) vs {} (expected)",
6973+
msg.next_remote_commitment_number,
6974+
our_commitment_transaction
6975+
)));
6976+
}
6977+
(None, None, None)
6978+
};
6979+
69226980
Ok(ReestablishResponses {
69236981
channel_ready, shutdown_msg, announcement_sigs,
69246982
raa: required_revoke,
6925-
commitment_update: None,
6983+
commitment_update,
69266984
order: self.context.resend_order.clone(),
6985+
tx_signatures,
6986+
tx_abort,
69276987
})
69286988
} else if msg.next_local_commitment_number == next_counterparty_commitment_number - 1 {
69296989
if required_revoke.is_some() || self.context.signer_pending_revoke_and_ack {
@@ -6938,6 +6998,8 @@ impl<SP: Deref> FundedChannel<SP> where
69386998
channel_ready, shutdown_msg, announcement_sigs,
69396999
commitment_update: None, raa: None,
69407000
order: self.context.resend_order.clone(),
7001+
tx_signatures: None,
7002+
tx_abort: None,
69417003
})
69427004
} else {
69437005
let commitment_update = if self.context.resend_order == RAACommitmentOrder::RevokeAndACKFirst
@@ -6960,6 +7022,8 @@ impl<SP: Deref> FundedChannel<SP> where
69607022
channel_ready, shutdown_msg, announcement_sigs,
69617023
raa, commitment_update,
69627024
order: self.context.resend_order.clone(),
7025+
tx_signatures: None,
7026+
tx_abort: None,
69637027
})
69647028
}
69657029
} else if msg.next_local_commitment_number < next_counterparty_commitment_number {
@@ -8250,7 +8314,7 @@ impl<SP: Deref> FundedChannel<SP> where
82508314
// to the txid of that interactive transaction, else we MUST NOT set it.
82518315
if let Some(signing_session) = &self.interactive_tx_signing_session {
82528316
// Since we have a signing_session, this implies we've sent an initial `commitment_signed`...
8253-
if !signing_session.counterparty_sent_tx_signatures {
8317+
if !signing_session.counterparty_sent_tx_signatures() {
82548318
// ...but we didn't receive a `tx_signatures` from the counterparty yet.
82558319
Some(self.funding_outpoint().txid)
82568320
} else {

Diff for: lightning/src/ln/channelmanager.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -3253,7 +3253,7 @@ macro_rules! handle_monitor_update_completion {
32533253
&mut $peer_state.pending_msg_events, $chan, updates.raa,
32543254
updates.commitment_update, updates.order, updates.accepted_htlcs, updates.pending_update_adds,
32553255
updates.funding_broadcastable, updates.channel_ready,
3256-
updates.announcement_sigs, updates.tx_signatures);
3256+
updates.announcement_sigs, updates.tx_signatures, None);
32573257
if let Some(upd) = channel_update {
32583258
$peer_state.pending_msg_events.push(upd);
32593259
}
@@ -7585,10 +7585,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
75857585
pending_forwards: Vec<(PendingHTLCInfo, u64)>, pending_update_adds: Vec<msgs::UpdateAddHTLC>,
75867586
funding_broadcastable: Option<Transaction>,
75877587
channel_ready: Option<msgs::ChannelReady>, announcement_sigs: Option<msgs::AnnouncementSignatures>,
7588-
tx_signatures: Option<msgs::TxSignatures>
7588+
tx_signatures: Option<msgs::TxSignatures>, tx_abort: Option<msgs::TxAbort>,
75897589
) -> (Option<(u64, Option<PublicKey>, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)>, Option<(u64, Vec<msgs::UpdateAddHTLC>)>) {
75907590
let logger = WithChannelContext::from(&self.logger, &channel.context, None);
7591-
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",
7591+
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",
75927592
&channel.context.channel_id(),
75937593
if raa.is_some() { "an" } else { "no" },
75947594
if commitment_update.is_some() { "a" } else { "no" },
@@ -7597,6 +7597,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
75977597
if channel_ready.is_some() { "sending" } else { "without" },
75987598
if announcement_sigs.is_some() { "sending" } else { "without" },
75997599
if tx_signatures.is_some() { "sending" } else { "without" },
7600+
if tx_abort.is_some() { "sending" } else { "without" },
76007601
);
76017602

76027603
let counterparty_node_id = channel.context.get_counterparty_node_id();
@@ -7630,6 +7631,12 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
76307631
msg,
76317632
});
76327633
}
7634+
if let Some(msg) = tx_abort {
7635+
pending_msg_events.push(events::MessageSendEvent::SendTxAbort {
7636+
node_id: counterparty_node_id,
7637+
msg,
7638+
});
7639+
}
76337640

76347641
macro_rules! handle_cs { () => {
76357642
if let Some(update) = commitment_update {
@@ -9401,7 +9408,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
94019408
let need_lnd_workaround = chan.context.workaround_lnd_bug_4006.take();
94029409
let (htlc_forwards, decode_update_add_htlcs) = self.handle_channel_resumption(
94039410
&mut peer_state.pending_msg_events, chan, responses.raa, responses.commitment_update, responses.order,
9404-
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs, None);
9411+
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs,
9412+
responses.tx_signatures, responses.tx_abort);
94059413
debug_assert!(htlc_forwards.is_none());
94069414
debug_assert!(decode_update_add_htlcs.is_none());
94079415
if let Some(upd) = channel_update {

Diff for: lightning/src/ln/interactivetxs.rs

+26-6
Original file line numberDiff line numberDiff line change
@@ -289,16 +289,36 @@ impl ConstructedTransaction {
289289
/// https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#sharing-funding-signatures-tx_signatures
290290
#[derive(Debug, Clone, PartialEq)]
291291
pub(crate) struct InteractiveTxSigningSession {
292-
pub unsigned_tx: ConstructedTransaction,
293-
pub counterparty_sent_tx_signatures: bool,
292+
unsigned_tx: ConstructedTransaction,
293+
counterparty_sent_tx_signatures: bool,
294294
holder_sends_tx_signatures_first: bool,
295-
received_commitment_signed: bool,
295+
has_received_commitment_signed: bool,
296296
holder_tx_signatures: Option<TxSignatures>,
297297
}
298298

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

309329
pub fn get_tx_signatures(&self) -> Option<TxSignatures> {
310-
if self.received_commitment_signed {
330+
if self.has_received_commitment_signed {
311331
self.holder_tx_signatures.clone()
312332
} else {
313333
None
@@ -988,7 +1008,7 @@ macro_rules! define_state_transitions {
9881008
let signing_session = InteractiveTxSigningSession {
9891009
holder_sends_tx_signatures_first: tx.holder_sends_tx_signatures_first,
9901010
unsigned_tx: tx,
991-
received_commitment_signed: false,
1011+
has_received_commitment_signed: false,
9921012
holder_tx_signatures: None,
9931013
counterparty_sent_tx_signatures: false,
9941014
};

0 commit comments

Comments
 (0)