Skip to content

Commit ff7a37f

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 ce08aec commit ff7a37f

File tree

3 files changed

+111
-17
lines changed

3 files changed

+111
-17
lines changed

lightning/src/ln/channel.rs

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,8 @@ pub(super) struct ReestablishResponses {
930930
pub order: RAACommitmentOrder,
931931
pub announcement_sigs: Option<msgs::AnnouncementSignatures>,
932932
pub shutdown_msg: Option<msgs::Shutdown>,
933+
pub tx_signatures: Option<msgs::TxSignatures>,
934+
pub tx_abort: Option<msgs::TxAbort>,
933935
}
934936

935937
/// The first message we send to our peer after connection
@@ -2115,7 +2117,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
21152117

21162118
let mut output_index = None;
21172119
let expected_spk = self.context.get_funding_redeemscript().to_p2wsh();
2118-
for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() {
2120+
for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() {
21192121
if outp.script_pubkey() == &expected_spk && outp.value() == self.context.get_value_satoshis() {
21202122
if output_index.is_some() {
21212123
return Err(ChannelError::Close(
@@ -2128,7 +2130,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
21282130
}
21292131
}
21302132
let outpoint = if let Some(output_index) = output_index {
2131-
OutPoint { txid: signing_session.unsigned_tx.compute_txid(), index: output_index }
2133+
OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
21322134
} else {
21332135
return Err(ChannelError::Close(
21342136
(
@@ -2143,7 +2145,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
21432145
let commitment_signed = self.context.get_initial_commitment_signed(logger);
21442146
let commitment_signed = match commitment_signed {
21452147
Ok(commitment_signed) => {
2146-
self.context.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx());
2148+
self.context.funding_transaction = Some(signing_session.unsigned_tx().build_unsigned_tx());
21472149
commitment_signed
21482150
},
21492151
Err(err) => {
@@ -6001,7 +6003,7 @@ impl<SP: Deref> FundedChannel<SP> where
60016003
}
60026004

60036005
if let Some(ref mut signing_session) = self.interactive_tx_signing_session {
6004-
if msg.tx_hash != signing_session.unsigned_tx.compute_txid() {
6006+
if msg.tx_hash != signing_session.unsigned_tx().compute_txid() {
60056007
return Err(ChannelError::Close(
60066008
(
60076009
"The txid for the transaction does not match".to_string(),
@@ -6631,7 +6633,7 @@ impl<SP: Deref> FundedChannel<SP> where
66316633
}
66326634

66336635
if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
6634-
msg.next_local_commitment_number == 0 {
6636+
msg.next_local_commitment_number == 0 && msg.next_funding_txid.is_none() {
66356637
return Err(ChannelError::close("Peer sent an invalid channel_reestablish to force close in a non-standard way".to_owned()));
66366638
}
66376639

@@ -6695,6 +6697,8 @@ impl<SP: Deref> FundedChannel<SP> where
66956697
raa: None, commitment_update: None,
66966698
order: RAACommitmentOrder::CommitmentFirst,
66976699
shutdown_msg, announcement_sigs,
6700+
tx_signatures: None,
6701+
tx_abort: None,
66986702
});
66996703
}
67006704

@@ -6704,6 +6708,8 @@ impl<SP: Deref> FundedChannel<SP> where
67046708
raa: None, commitment_update: None,
67056709
order: RAACommitmentOrder::CommitmentFirst,
67066710
shutdown_msg, announcement_sigs,
6711+
tx_signatures: None,
6712+
tx_abort: None,
67076713
});
67086714
}
67096715

@@ -6749,11 +6755,67 @@ impl<SP: Deref> FundedChannel<SP> where
67496755
log_debug!(logger, "Reconnected channel {} with no loss", &self.context.channel_id());
67506756
}
67516757

6758+
// if next_funding_txid is set:
6759+
let (commitment_update, tx_signatures, tx_abort) = if let Some(next_funding_txid) = msg.next_funding_txid {
6760+
if let Some(session) = &self.interactive_tx_signing_session {
6761+
// if next_funding_txid matches the latest interactive funding transaction:
6762+
if session.unsigned_tx().compute_txid() == next_funding_txid {
6763+
// if it has not received tx_signatures for that funding transaction:
6764+
if !session.counterparty_sent_tx_signatures() {
6765+
// if next_commitment_number is zero:
6766+
let commitment_update = if msg.next_local_commitment_number == 0 {
6767+
// MUST retransmit its commitment_signed for that funding transaction.
6768+
let commitment_signed = self.context.get_initial_commitment_signed(logger)?;
6769+
Some(msgs::CommitmentUpdate {
6770+
commitment_signed,
6771+
update_add_htlcs: vec![],
6772+
update_fulfill_htlcs: vec![],
6773+
update_fail_htlcs: vec![],
6774+
update_fail_malformed_htlcs: vec![],
6775+
update_fee: None,
6776+
})
6777+
} else { None };
6778+
// if it has already received commitment_signed and it should sign first, as specified in the tx_signatures requirements:
6779+
if session.has_received_commitment_signed() && session.holder_sends_tx_signatures_first() {
6780+
// MUST send its tx_signatures for that funding transaction.
6781+
(commitment_update, session.holder_tx_signatures().clone(), None)
6782+
} else {
6783+
(commitment_update, None, None)
6784+
}
6785+
} else {
6786+
// if it has already received tx_signatures for that funding transaction:
6787+
// MUST send its tx_signatures for that funding transaction.
6788+
(None, session.holder_tx_signatures().clone(), None)
6789+
}
6790+
} else {
6791+
// MUST send tx_abort to let the sending node know that they can forget this funding transaction.
6792+
(None, None, Some(msgs::TxAbort { channel_id: self.context.channel_id(), data: vec![] }))
6793+
}
6794+
} else {
6795+
// Counterparty set `next_funding_txid` at incorrect state.
6796+
// TODO(dual_funding): Should probably error here (or send tx_abort) but not in spec.
6797+
(None, None, None)
6798+
}
6799+
} else {
6800+
// if `next_funding_txid` is not set, and `next_commitment_number` is zero:
6801+
if msg.next_local_commitment_number == 0 {
6802+
// MUST immediately fail the channel and broadcast any relevant latest commitment transaction.
6803+
return Err(ChannelError::close(format!(
6804+
"Peer attempted to reestablish channel expecting a future local commitment transaction: {} (received) vs {} (expected)",
6805+
msg.next_remote_commitment_number,
6806+
our_commitment_transaction
6807+
)));
6808+
}
6809+
(None, None, None)
6810+
};
6811+
67526812
Ok(ReestablishResponses {
67536813
channel_ready, shutdown_msg, announcement_sigs,
67546814
raa: required_revoke,
6755-
commitment_update: None,
6815+
commitment_update,
67566816
order: self.context.resend_order.clone(),
6817+
tx_signatures,
6818+
tx_abort,
67576819
})
67586820
} else if msg.next_local_commitment_number == next_counterparty_commitment_number - 1 {
67596821
if required_revoke.is_some() || self.context.signer_pending_revoke_and_ack {
@@ -6768,6 +6830,8 @@ impl<SP: Deref> FundedChannel<SP> where
67686830
channel_ready, shutdown_msg, announcement_sigs,
67696831
commitment_update: None, raa: None,
67706832
order: self.context.resend_order.clone(),
6833+
tx_signatures: None,
6834+
tx_abort: None,
67716835
})
67726836
} else {
67736837
let commitment_update = if self.context.resend_order == RAACommitmentOrder::RevokeAndACKFirst
@@ -6790,6 +6854,8 @@ impl<SP: Deref> FundedChannel<SP> where
67906854
channel_ready, shutdown_msg, announcement_sigs,
67916855
raa, commitment_update,
67926856
order: self.context.resend_order.clone(),
6857+
tx_signatures: None,
6858+
tx_abort: None,
67936859
})
67946860
}
67956861
} else if msg.next_local_commitment_number < next_counterparty_commitment_number {
@@ -8067,7 +8133,7 @@ impl<SP: Deref> FundedChannel<SP> where
80678133
// to the txid of that interactive transaction, else we MUST NOT set it.
80688134
if let Some(signing_session) = &self.interactive_tx_signing_session {
80698135
// Since we have a signing_session, this implies we've sent an initial `commitment_signed`...
8070-
if !signing_session.counterparty_sent_tx_signatures {
8136+
if !signing_session.counterparty_sent_tx_signatures() {
80718137
// ...but we didn't receive a `tx_signatures` from the counterparty yet.
80728138
Some(self.funding_outpoint().txid)
80738139
} else {

lightning/src/ln/channelmanager.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3207,7 +3207,7 @@ macro_rules! handle_monitor_update_completion {
32073207
&mut $peer_state.pending_msg_events, $chan, updates.raa,
32083208
updates.commitment_update, updates.order, updates.accepted_htlcs, updates.pending_update_adds,
32093209
updates.funding_broadcastable, updates.channel_ready,
3210-
updates.announcement_sigs, updates.tx_signatures);
3210+
updates.announcement_sigs, updates.tx_signatures, None);
32113211
if let Some(upd) = channel_update {
32123212
$peer_state.pending_msg_events.push(upd);
32133213
}
@@ -7470,10 +7470,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
74707470
pending_forwards: Vec<(PendingHTLCInfo, u64)>, pending_update_adds: Vec<msgs::UpdateAddHTLC>,
74717471
funding_broadcastable: Option<Transaction>,
74727472
channel_ready: Option<msgs::ChannelReady>, announcement_sigs: Option<msgs::AnnouncementSignatures>,
7473-
tx_signatures: Option<msgs::TxSignatures>
7473+
tx_signatures: Option<msgs::TxSignatures>, tx_abort: Option<msgs::TxAbort>,
74747474
) -> (Option<(u64, Option<PublicKey>, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)>, Option<(u64, Vec<msgs::UpdateAddHTLC>)>) {
74757475
let logger = WithChannelContext::from(&self.logger, &channel.context, None);
7476-
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",
7476+
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",
74777477
&channel.context.channel_id(),
74787478
if raa.is_some() { "an" } else { "no" },
74797479
if commitment_update.is_some() { "a" } else { "no" },
@@ -7482,6 +7482,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
74827482
if channel_ready.is_some() { "sending" } else { "without" },
74837483
if announcement_sigs.is_some() { "sending" } else { "without" },
74847484
if tx_signatures.is_some() { "sending" } else { "without" },
7485+
if tx_abort.is_some() { "sending" } else { "without" },
74857486
);
74867487

74877488
let counterparty_node_id = channel.context.get_counterparty_node_id();
@@ -7515,6 +7516,12 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
75157516
msg,
75167517
});
75177518
}
7519+
if let Some(msg) = tx_abort {
7520+
pending_msg_events.push(events::MessageSendEvent::SendTxAbort {
7521+
node_id: counterparty_node_id,
7522+
msg,
7523+
});
7524+
}
75187525

75197526
macro_rules! handle_cs { () => {
75207527
if let Some(update) = commitment_update {
@@ -9186,7 +9193,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
91869193
let need_lnd_workaround = chan.context.workaround_lnd_bug_4006.take();
91879194
let (htlc_forwards, decode_update_add_htlcs) = self.handle_channel_resumption(
91889195
&mut peer_state.pending_msg_events, chan, responses.raa, responses.commitment_update, responses.order,
9189-
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs, None);
9196+
Vec::new(), Vec::new(), None, responses.channel_ready, responses.announcement_sigs,
9197+
responses.tx_signatures, responses.tx_abort);
91909198
debug_assert!(htlc_forwards.is_none());
91919199
debug_assert!(decode_update_add_htlcs.is_none());
91929200
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
@@ -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)