Time out AwatingRemoteRAA outgoing HTLCs when we reach cltv_expiry
[rust-lightning] / lightning / src / ln / channelmanager.rs
index b616567073eb9741f1e0ebbfaa2385440f9be954..cbcccb82f933f7416c7ad5a44e3a5c196ec51391 100644 (file)
@@ -1225,6 +1225,80 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
                })
        }
 
+       // Only public for testing, this should otherwise never be called direcly
+       pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32) -> Result<(), APIError> {
+               log_trace!(self, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
+               let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
+
+               let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
+                       .map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
+               let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height)?;
+               if onion_utils::route_size_insane(&onion_payloads) {
+                       return Err(APIError::RouteError{err: "Route size too large considering onion data"});
+               }
+               let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash);
+
+               let _ = self.total_consistency_lock.read().unwrap();
+
+               let err: Result<(), _> = loop {
+                       let mut channel_lock = self.channel_state.lock().unwrap();
+                       let id = match channel_lock.short_to_id.get(&path.first().unwrap().short_channel_id) {
+                               None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"}),
+                               Some(id) => id.clone(),
+                       };
+
+                       let channel_state = &mut *channel_lock;
+                       if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
+                               match {
+                                       if chan.get().get_their_node_id() != path.first().unwrap().pubkey {
+                                               return Err(APIError::RouteError{err: "Node ID mismatch on first hop!"});
+                                       }
+                                       if !chan.get().is_live() {
+                                               return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"});
+                                       }
+                                       break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
+                                               path: path.clone(),
+                                               session_priv: session_priv.clone(),
+                                               first_hop_htlc_msat: htlc_msat,
+                                       }, onion_packet), channel_state, chan)
+                               } {
+                                       Some((update_add, commitment_signed, monitor_update)) => {
+                                               if let Err(e) = self.monitor.update_monitor(chan.get().get_funding_txo().unwrap(), monitor_update) {
+                                                       maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
+                                                       // Note that MonitorUpdateFailed here indicates (per function docs)
+                                                       // that we will resend the commitment update once monitor updating
+                                                       // is restored. Therefore, we must return an error indicating that
+                                                       // it is unsafe to retry the payment wholesale, which we do in the
+                                                       // send_payment check for MonitorUpdateFailed, below.
+                                                       return Err(APIError::MonitorUpdateFailed);
+                                               }
+
+                                               channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
+                                                       node_id: path.first().unwrap().pubkey,
+                                                       updates: msgs::CommitmentUpdate {
+                                                               update_add_htlcs: vec![update_add],
+                                                               update_fulfill_htlcs: Vec::new(),
+                                                               update_fail_htlcs: Vec::new(),
+                                                               update_fail_malformed_htlcs: Vec::new(),
+                                                               update_fee: None,
+                                                               commitment_signed,
+                                                       },
+                                               });
+                                       },
+                                       None => {},
+                               }
+                       } else { unreachable!(); }
+                       return Ok(());
+               };
+
+               match handle_error!(self, err, path.first().unwrap().pubkey) {
+                       Ok(_) => unreachable!(),
+                       Err(e) => {
+                               Err(APIError::ChannelUnavailable { err: e.err })
+                       },
+               }
+       }
+
        /// Sends a payment along a given route.
        ///
        /// Value parameters are provided via the last hop in route, see documentation for RouteHop
@@ -1297,89 +1371,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref> ChannelMan
 
                let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
                let mut results = Vec::new();
-               'path_loop: for path in route.paths.iter() {
-                       macro_rules! check_res_push {
-                               ($res: expr) => { match $res {
-                                               Ok(r) => r,
-                                               Err(e) => {
-                                                       results.push(Err(e));
-                                                       continue 'path_loop;
-                                               },
-                                       }
-                               }
-                       }
-
-                       log_trace!(self, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
-                       let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
-
-                       let onion_keys = check_res_push!(onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
-                               .map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"}));
-                       let (onion_payloads, htlc_msat, htlc_cltv) = check_res_push!(onion_utils::build_onion_payloads(&path, total_value, payment_secret, cur_height));
-                       if onion_utils::route_size_insane(&onion_payloads) {
-                               check_res_push!(Err(APIError::RouteError{err: "Route size too large considering onion data"}));
-                       }
-                       let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
-
-                       let _ = self.total_consistency_lock.read().unwrap();
-
-                       let err: Result<(), _> = loop {
-                               let mut channel_lock = self.channel_state.lock().unwrap();
-                               let id = match channel_lock.short_to_id.get(&path.first().unwrap().short_channel_id) {
-                                       None => check_res_push!(Err(APIError::ChannelUnavailable{err: "No channel available with first hop!"})),
-                                       Some(id) => id.clone(),
-                               };
-
-                               let channel_state = &mut *channel_lock;
-                               if let hash_map::Entry::Occupied(mut chan) = channel_state.by_id.entry(id) {
-                                       match {
-                                               if chan.get().get_their_node_id() != path.first().unwrap().pubkey {
-                                                       check_res_push!(Err(APIError::RouteError{err: "Node ID mismatch on first hop!"}));
-                                               }
-                                               if !chan.get().is_live() {
-                                                       check_res_push!(Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected/pending monitor update!"}));
-                                               }
-                                               break_chan_entry!(self, chan.get_mut().send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute {
-                                                       path: path.clone(),
-                                                       session_priv: session_priv.clone(),
-                                                       first_hop_htlc_msat: htlc_msat,
-                                               }, onion_packet), channel_state, chan)
-                                       } {
-                                               Some((update_add, commitment_signed, monitor_update)) => {
-                                                       if let Err(e) = self.monitor.update_monitor(chan.get().get_funding_txo().unwrap(), monitor_update) {
-                                                               maybe_break_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::CommitmentFirst, false, true);
-                                                               // Note that MonitorUpdateFailed here indicates (per function docs)
-                                                               // that we will resend the commitment update once monitor updating
-                                                               // is restored. Therefore, we must return an error indicating that
-                                                               // it is unsafe to retry the payment wholesale, which we do in the
-                                                               // next check for MonitorUpdateFailed, below.
-                                                               check_res_push!(Err(APIError::MonitorUpdateFailed));
-                                                       }
-
-                                                       channel_state.pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs {
-                                                               node_id: path.first().unwrap().pubkey,
-                                                               updates: msgs::CommitmentUpdate {
-                                                                       update_add_htlcs: vec![update_add],
-                                                                       update_fulfill_htlcs: Vec::new(),
-                                                                       update_fail_htlcs: Vec::new(),
-                                                                       update_fail_malformed_htlcs: Vec::new(),
-                                                                       update_fee: None,
-                                                                       commitment_signed,
-                                                               },
-                                                       });
-                                               },
-                                               None => {},
-                                       }
-                               } else { unreachable!(); }
-                               results.push(Ok(()));
-                               continue 'path_loop;
-                       };
-
-                       match handle_error!(self, err, path.first().unwrap().pubkey) {
-                               Ok(_) => unreachable!(),
-                               Err(e) => {
-                                       check_res_push!(Err(APIError::ChannelUnavailable { err: e.err }));
-                               },
-                       }
+               for path in route.paths.iter() {
+                       results.push(self.send_payment_along_path(&path, &payment_hash, payment_secret, total_value, cur_height));
                }
                let mut has_ok = false;
                let mut has_err = false;
@@ -2969,23 +2962,32 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
                        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) {
-                                               log_trace!(self, "Sending funding_locked and announcement_signatures for {}", log_bytes!(channel.channel_id()));
-                                               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 {
+                                       for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
+                                               let chan_update = self.get_channel_update(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
+                                               timed_out_htlcs.push((source, payment_hash,  HTLCFailReason::Reason {
+                                                       failure_code: 0x1000 | 14, // expiry_too_soon, or at least it is now
+                                                       data: chan_update,
+                                               }));
+                                       }
+                                       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,
                                                });
-                                       } else {
-                                               log_trace!(self, "Sending funding_locked WITHOUT announcement_signatures for {}", log_bytes!(channel.channel_id()));
+                                               if let Some(announcement_sigs) = self.get_announcement_sigs(channel) {
+                                                       log_trace!(self, "Sending funding_locked and announcement_signatures for {}", log_bytes!(channel.channel_id()));
+                                                       pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
+                                                               node_id: channel.get_their_node_id(),
+                                                               msg: announcement_sigs,
+                                                       });
+                                               } else {
+                                                       log_trace!(self, "Sending funding_locked WITHOUT announcement_signatures for {}", log_bytes!(channel.channel_id()));
+                                               }
+                                               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 },
@@ -3056,8 +3058,6 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
                }
 
                for (source, payment_hash, reason) in timed_out_htlcs.drain(..) {
-                       // Call it incorrect_or_unknown_payment_details as the issue, ultimately, is that the
-                       // user failed to provide us a preimage within the cltv_expiry time window.
                        self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason);
                }
                self.latest_block_height.store(height as usize, Ordering::Release);