Time out AwatingRemoteRAA outgoing HTLCs when we reach cltv_expiry
authorAntoine Riard <ariard@student.42.fr>
Sat, 8 Dec 2018 03:09:58 +0000 (22:09 -0500)
committerMatt Corallo <git@bluematt.me>
Sat, 25 Jan 2020 22:12:08 +0000 (17:12 -0500)
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

lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs

index 8caa88854efb1007b5ec10996426e9fa6fc9c8ff..b50a701f17c1c3c016085ab98131403a491e21f1 100644 (file)
@@ -2964,12 +2964,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
        }
 
        /// 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<Option<msgs::FundingLocked>, msgs::ErrorMessage> {
+       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> {
+               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<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                                                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<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                                }
                        }
                }
-               Ok(None)
+               Ok((None, timed_out_htlcs))
        }
 
        /// Called by channelmanager based on chain blocks being disconnected.
index eb1fabecca1ae0d8cbdffd838ac3cc0049ff1f33..74c10fd5817905da61c1a87e3e656e5e3b07e61f 100644 (file)
@@ -2802,20 +2802,26 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send> 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 },