Skip to content

Commit fe620cb

Browse files
Antoine RiardTheBlueMatt
Antoine Riard
authored andcommitted
Time out AwatingRemoteRAA outgoing HTLCs when we reach cltv_expiry
In case of committing out-of-time outgoing HTLCs, we force ourselves to close the channel to avoid remote peer claims on a non-backed HTLC
1 parent ea47426 commit fe620cb

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

lightning/src/ln/channel.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2961,12 +2961,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
29612961
}
29622962

29632963
/// Called by channelmanager based on chain blocks being connected.
2964-
/// Note that we only need to use this to detect funding_signed, anything else is handled by
2965-
/// the channel_monitor.
2964+
/// We need to use this to detect funding_signed and outgoing HTLC timed out before we were able
2965+
/// to commit them on remote commitment tx, anything else is handled by the channel_monitor.
29662966
/// In case of Err, the channel may have been closed, at which point the standard requirements
29672967
/// apply - no calls may be made except those explicitly stated to be allowed post-shutdown.
29682968
/// Only returns an ErrorAction of DisconnectPeer, if Err.
2969-
pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, msgs::ErrorMessage> {
2969+
pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash, u64)>), msgs::ErrorMessage> {
2970+
let mut timed_out_htlcs = Vec::new();
2971+
self.holding_cell_htlc_updates.retain(|htlc_update| {
2972+
match htlc_update {
2973+
&HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, ref amount_msat, .. } => {
2974+
if cltv_expiry <= &height { // XXX follow 0a4821b
2975+
timed_out_htlcs.push((source.clone(), payment_hash.clone(), *amount_msat));
2976+
false
2977+
} else { true }
2978+
},
2979+
_ => true
2980+
}
2981+
});
29702982
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
29712983
if header.bitcoin_hash() != self.last_block_connected {
29722984
self.last_block_connected = header.bitcoin_hash();
@@ -3002,13 +3014,13 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
30023014
if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 {
30033015
let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
30043016
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret);
3005-
return Ok(Some(msgs::FundingLocked {
3017+
return Ok((Some(msgs::FundingLocked {
30063018
channel_id: self.channel_id,
30073019
next_per_commitment_point: next_per_commitment_point,
3008-
}));
3020+
}), timed_out_htlcs));
30093021
} else {
30103022
self.monitor_pending_funding_locked = true;
3011-
return Ok(None);
3023+
return Ok((None, timed_out_htlcs));
30123024
}
30133025
}
30143026
}
@@ -3054,7 +3066,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
30543066
}
30553067
}
30563068
}
3057-
Ok(None)
3069+
Ok((None, timed_out_htlcs))
30583070
}
30593071

30603072
/// Called by channelmanager based on chain blocks being disconnected.

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,20 +2821,26 @@ impl<ChanSigner: ChannelKeys> ChainListener for ChannelManager<ChanSigner> {
28212821
let short_to_id = channel_state.short_to_id;
28222822
let pending_msg_events = channel_state.pending_msg_events;
28232823
channel_state.by_id.retain(|_, channel| {
2824-
let chan_res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched);
2825-
if let Ok(Some(funding_locked)) = chan_res {
2826-
pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
2827-
node_id: channel.get_their_node_id(),
2828-
msg: funding_locked,
2829-
});
2830-
if let Some(announcement_sigs) = self.get_announcement_sigs(channel) {
2831-
pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
2824+
let res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched);
2825+
if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
2826+
timed_out_htlcs.reserve(timed_out_pending_htlcs.len());
2827+
for (htlc_src, payment_hash, value) in timed_out_pending_htlcs.drain(..) {
2828+
timed_out_htlcs.push((htlc_src, payment_hash, value));
2829+
}
2830+
if let Some(funding_locked) = chan_res {
2831+
pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
28322832
node_id: channel.get_their_node_id(),
2833-
msg: announcement_sigs,
2833+
msg: funding_locked,
28342834
});
2835+
if let Some(announcement_sigs) = self.get_announcement_sigs(channel) {
2836+
pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
2837+
node_id: channel.get_their_node_id(),
2838+
msg: announcement_sigs,
2839+
});
2840+
}
2841+
short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
28352842
}
2836-
short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
2837-
} else if let Err(e) = chan_res {
2843+
} else if let Err(e) = res {
28382844
pending_msg_events.push(events::MessageSendEvent::HandleError {
28392845
node_id: channel.get_their_node_id(),
28402846
action: msgs::ErrorAction::SendErrorMessage { msg: e },

0 commit comments

Comments
 (0)