From: Antoine Riard Date: Sat, 8 Dec 2018 03:09:58 +0000 (-0500) Subject: Time out AwatingRemoteRAA outgoing HTLCs when we reach cltv_expiry X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=2ca98c9a6246966833ccd1274c7f49296fec9af2;p=rust-lightning 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 --- diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 8caa88854..b50a701f1 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -2964,12 +2964,24 @@ impl Channel { } /// Called by channelmanager based on chain blocks being connected. - /// Note that we only need to use this to detect funding_signed, anything else is handled by - /// the channel_monitor. + /// We need to use this to detect funding_signed and outgoing HTLC timed out before we were able + /// to commit them on remote commitment tx, anything else is handled by the channel_monitor. /// In case of Err, the channel may have been closed, at which point the standard requirements /// apply - no calls may be made except those explicitly stated to be allowed post-shutdown. /// Only returns an ErrorAction of DisconnectPeer, if Err. - pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result, msgs::ErrorMessage> { + pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<(Option, Vec<(HTLCSource, PaymentHash, u64)>), msgs::ErrorMessage> { + let mut timed_out_htlcs = Vec::new(); + self.holding_cell_htlc_updates.retain(|htlc_update| { + match htlc_update { + &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, ref amount_msat, .. } => { + if cltv_expiry <= &height { // XXX follow 0a4821b + timed_out_htlcs.push((source.clone(), payment_hash.clone(), *amount_msat)); + false + } else { true } + }, + _ => true + } + }); let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); if header.bitcoin_hash() != self.last_block_connected { self.last_block_connected = header.bitcoin_hash(); @@ -3005,13 +3017,13 @@ impl Channel { if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number); let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret); - return Ok(Some(msgs::FundingLocked { + return Ok((Some(msgs::FundingLocked { channel_id: self.channel_id, next_per_commitment_point: next_per_commitment_point, - })); + }), timed_out_htlcs)); } else { self.monitor_pending_funding_locked = true; - return Ok(None); + return Ok((None, timed_out_htlcs)); } } } @@ -3057,7 +3069,7 @@ impl Channel { } } } - Ok(None) + Ok((None, timed_out_htlcs)) } /// Called by channelmanager based on chain blocks being disconnected. diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index c7d7e3085..770ef3dbb 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2804,20 +2804,26 @@ impl ChainListener for ChannelM let short_to_id = &mut channel_state.short_to_id; let pending_msg_events = &mut channel_state.pending_msg_events; channel_state.by_id.retain(|_, channel| { - let chan_res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched); - if let Ok(Some(funding_locked)) = chan_res { - pending_msg_events.push(events::MessageSendEvent::SendFundingLocked { - node_id: channel.get_their_node_id(), - msg: funding_locked, - }); - if let Some(announcement_sigs) = self.get_announcement_sigs(channel) { - pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { + let res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched); + if let Ok((chan_res, mut timed_out_pending_htlcs)) = res { + timed_out_htlcs.reserve(timed_out_pending_htlcs.len()); + for (htlc_src, payment_hash, value) in timed_out_pending_htlcs.drain(..) { + timed_out_htlcs.push((htlc_src, payment_hash, value)); + } + if let Some(funding_locked) = chan_res { + pending_msg_events.push(events::MessageSendEvent::SendFundingLocked { node_id: channel.get_their_node_id(), - msg: announcement_sigs, + msg: funding_locked, }); + if let Some(announcement_sigs) = self.get_announcement_sigs(channel) { + pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { + node_id: channel.get_their_node_id(), + msg: announcement_sigs, + }); + } + short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id()); } - short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id()); - } else if let Err(e) = chan_res { + } else if let Err(e) = res { pending_msg_events.push(events::MessageSendEvent::HandleError { node_id: channel.get_their_node_id(), action: msgs::ErrorAction::SendErrorMessage { msg: e },