Penalize failed channels in Scorer
[rust-lightning] / lightning / src / ln / channelmanager.rs
index 63c4bcc6b13813df6ef93472532ab4e67bb5ef4b..e6c27efc8eccdb332c98b17e314284b5ceb3c4ff 100644 (file)
@@ -45,7 +45,7 @@ use chain::transaction::{OutPoint, TransactionData};
 use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch};
 use ln::features::{InitFeatures, NodeFeatures};
-use routing::router::{Route, RouteHop};
+use routing::router::{Payee, Route, RouteHop, RouteParameters};
 use ln::msgs;
 use ln::msgs::NetAddress;
 use ln::onion_utils;
@@ -201,6 +201,7 @@ pub(crate) enum HTLCSource {
                first_hop_htlc_msat: u64,
                payment_id: PaymentId,
                payment_secret: Option<PaymentSecret>,
+               payee: Option<Payee>,
        },
 }
 #[allow(clippy::derive_hash_xor_eq)] // Our Hash is faithful to the data, we just don't have SecretKey::hash
@@ -211,13 +212,14 @@ impl core::hash::Hash for HTLCSource {
                                0u8.hash(hasher);
                                prev_hop_data.hash(hasher);
                        },
-                       HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat } => {
+                       HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat, payee } => {
                                1u8.hash(hasher);
                                path.hash(hasher);
                                session_priv[..].hash(hasher);
                                payment_id.hash(hasher);
                                payment_secret.hash(hasher);
                                first_hop_htlc_msat.hash(hasher);
+                               payee.hash(hasher);
                        },
                }
        }
@@ -231,6 +233,7 @@ impl HTLCSource {
                        first_hop_htlc_msat: 0,
                        payment_id: PaymentId([2; 32]),
                        payment_secret: None,
+                       payee: None,
                }
        }
 }
@@ -2021,7 +2024,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        }
 
        // 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, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
+       pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payee: &Option<Payee>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
                log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
                let prng_seed = self.keys_manager.get_secure_random_bytes();
                let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
@@ -2071,6 +2074,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                        first_hop_htlc_msat: htlc_msat,
                                                        payment_id,
                                                        payment_secret: payment_secret.clone(),
+                                                       payee: payee.clone(),
                                                }, onion_packet, &self.logger),
                                        channel_state, chan);
 
@@ -2209,7 +2213,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                let cur_height = self.best_block.read().unwrap().height() + 1;
                let mut results = Vec::new();
                for path in route.paths.iter() {
-                       results.push(self.send_payment_along_path(&path, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage));
+                       results.push(self.send_payment_along_path(&path, &route.payee, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage));
                }
                let mut has_ok = false;
                let mut has_err = false;
@@ -3098,23 +3102,32 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        self.fail_htlc_backwards_internal(channel_state,
                                                htlc_src, &payment_hash, HTLCFailReason::Reason { failure_code, data: onion_failure_data});
                                },
-                               HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
+                               HTLCSource::OutboundRoute { session_priv, payment_id, path, payee, .. } => {
                                        let mut session_priv_bytes = [0; 32];
                                        session_priv_bytes.copy_from_slice(&session_priv[..]);
                                        let mut outbounds = self.pending_outbound_payments.lock().unwrap();
                                        if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
-                                               if payment.get_mut().remove(&session_priv_bytes, Some(path.last().unwrap().fee_msat)) &&
+                                               let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
+                                               if payment.get_mut().remove(&session_priv_bytes, Some(path_last_hop.fee_msat)) &&
                                                        !payment.get().is_fulfilled()
                                                {
+                                                       let retry = if let Some(payee_data) = payee {
+                                                               Some(RouteParameters {
+                                                                       payee: payee_data,
+                                                                       final_value_msat: path_last_hop.fee_msat,
+                                                                       final_cltv_expiry_delta: path_last_hop.cltv_expiry_delta,
+                                                               })
+                                                       } else { None };
                                                        self.pending_events.lock().unwrap().push(
                                                                events::Event::PaymentPathFailed {
+                                                                       payment_id: Some(payment_id),
                                                                        payment_hash,
                                                                        rejected_by_dest: false,
                                                                        network_update: None,
                                                                        all_paths_failed: payment.get().remaining_parts() == 0,
                                                                        path: path.clone(),
                                                                        short_channel_id: None,
-                                                                       retry: None,
+                                                                       retry,
                                                                        #[cfg(test)]
                                                                        error_code: None,
                                                                        #[cfg(test)]
@@ -3146,13 +3159,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                // from block_connected which may run during initialization prior to the chain_monitor
                // being fully configured. See the docs for `ChannelManagerReadArgs` for more.
                match source {
-                       HTLCSource::OutboundRoute { ref path, session_priv, payment_id, .. } => {
+                       HTLCSource::OutboundRoute { ref path, session_priv, payment_id, ref payee, .. } => {
                                let mut session_priv_bytes = [0; 32];
                                session_priv_bytes.copy_from_slice(&session_priv[..]);
                                let mut outbounds = self.pending_outbound_payments.lock().unwrap();
                                let mut all_paths_failed = false;
+                               let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
                                if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
-                                       if !payment.get_mut().remove(&session_priv_bytes, Some(path.last().unwrap().fee_msat)) {
+                                       if !payment.get_mut().remove(&session_priv_bytes, Some(path_last_hop.fee_msat)) {
                                                log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
                                                return;
                                        }
@@ -3167,8 +3181,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
                                        return;
                                }
-                               log_trace!(self.logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
                                mem::drop(channel_state_lock);
+                               let retry = if let Some(payee_data) = payee {
+                                       Some(RouteParameters {
+                                               payee: payee_data.clone(),
+                                               final_value_msat: path_last_hop.fee_msat,
+                                               final_cltv_expiry_delta: path_last_hop.cltv_expiry_delta,
+                                       })
+                               } else { None };
+                               log_trace!(self.logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
                                match &onion_error {
                                        &HTLCFailReason::LightningError { ref err } => {
 #[cfg(test)]
@@ -3180,13 +3201,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                // next-hop is needlessly blaming us!
                                                self.pending_events.lock().unwrap().push(
                                                        events::Event::PaymentPathFailed {
+                                                               payment_id: Some(payment_id),
                                                                payment_hash: payment_hash.clone(),
                                                                rejected_by_dest: !payment_retryable,
                                                                network_update,
                                                                all_paths_failed,
                                                                path: path.clone(),
                                                                short_channel_id,
-                                                               retry: None,
+                                                               retry,
 #[cfg(test)]
                                                                error_code: onion_error_code,
 #[cfg(test)]
@@ -3209,13 +3231,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                // channel here as we apparently can't relay through them anyway.
                                                self.pending_events.lock().unwrap().push(
                                                        events::Event::PaymentPathFailed {
+                                                               payment_id: Some(payment_id),
                                                                payment_hash: payment_hash.clone(),
                                                                rejected_by_dest: path.len() == 1,
                                                                network_update: None,
                                                                all_paths_failed,
                                                                path: path.clone(),
                                                                short_channel_id: Some(path.first().unwrap().short_channel_id),
-                                                               retry: None,
+                                                               retry,
 #[cfg(test)]
                                                                error_code: Some(*failure_code),
 #[cfg(test)]
@@ -3455,6 +3478,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
                                        self.pending_events.lock().unwrap().push(
                                                events::Event::PaymentSent {
+                                                       payment_id: Some(payment_id),
                                                        payment_preimage,
                                                        payment_hash: payment_hash
                                                }
@@ -5378,12 +5402,14 @@ impl Readable for HTLCSource {
                                let mut path = Some(Vec::new());
                                let mut payment_id = None;
                                let mut payment_secret = None;
+                               let mut payee = None;
                                read_tlv_fields!(reader, {
                                        (0, session_priv, required),
                                        (1, payment_id, option),
                                        (2, first_hop_htlc_msat, required),
                                        (3, payment_secret, option),
                                        (4, path, vec_type),
+                                       (5, payee, option),
                                });
                                if payment_id.is_none() {
                                        // For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -5396,6 +5422,7 @@ impl Readable for HTLCSource {
                                        path: path.unwrap(),
                                        payment_id: payment_id.unwrap(),
                                        payment_secret,
+                                       payee,
                                })
                        }
                        1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
@@ -5407,7 +5434,7 @@ impl Readable for HTLCSource {
 impl Writeable for HTLCSource {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
                match self {
-                       HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret } => {
+                       HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payee } => {
                                0u8.write(writer)?;
                                let payment_id_opt = Some(payment_id);
                                write_tlv_fields!(writer, {
@@ -5416,6 +5443,7 @@ impl Writeable for HTLCSource {
                                        (2, first_hop_htlc_msat, required),
                                        (3, payment_secret, option),
                                        (4, path, vec_type),
+                                       (5, payee, option),
                                 });
                        }
                        HTLCSource::PreviousHopData(ref field) => {
@@ -6008,15 +6036,14 @@ mod tests {
        use core::time::Duration;
        use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use ln::channelmanager::{PaymentId, PaymentSendFailure};
-       use ln::features::{InitFeatures, InvoiceFeatures};
+       use ln::features::InitFeatures;
        use ln::functional_test_utils::*;
        use ln::msgs;
        use ln::msgs::ChannelMessageHandler;
-       use routing::router::{Payee, get_keysend_route, get_route};
+       use routing::router::{Payee, RouteParameters, find_route};
        use routing::scorer::Scorer;
        use util::errors::APIError;
        use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
-       use util::test_utils;
 
        #[cfg(feature = "std")]
        #[test]
@@ -6160,7 +6187,7 @@ mod tests {
                // Use the utility function send_payment_along_path to send the payment with MPP data which
                // indicates there are more HTLCs coming.
                let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match.
-               nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
+               nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
                check_added_monitors!(nodes[0], 1);
                let mut events = nodes[0].node.get_and_clear_pending_msg_events();
                assert_eq!(events.len(), 1);
@@ -6190,7 +6217,7 @@ mod tests {
                expect_payment_failed!(nodes[0], our_payment_hash, true);
 
                // Send the second half of the original MPP payment.
-               nodes[0].node.send_payment_along_path(&route.paths[0], &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
+               nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
                check_added_monitors!(nodes[0], 1);
                let mut events = nodes[0].node.get_and_clear_pending_msg_events();
                assert_eq!(events.len(), 1);
@@ -6232,7 +6259,8 @@ mod tests {
                // further events will be generated for subsequence path successes.
                let events = nodes[0].node.get_and_clear_pending_events();
                match events[0] {
-                       Event::PaymentSent { payment_preimage: ref preimage, payment_hash: ref hash } => {
+                       Event::PaymentSent { payment_id: ref id, payment_preimage: ref preimage, payment_hash: ref hash } => {
+                               assert_eq!(Some(payment_id), *id);
                                assert_eq!(payment_preimage, *preimage);
                                assert_eq!(our_payment_hash, *hash);
                        },
@@ -6251,17 +6279,22 @@ mod tests {
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
                create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
-               let logger = test_utils::TestLogger::new();
-               let scorer = Scorer::new(0);
+               let scorer = Scorer::with_fixed_penalty(0);
 
                // To start (1), send a regular payment but don't claim it.
                let expected_route = [&nodes[1]];
                let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &expected_route, 100_000);
 
                // Next, attempt a keysend payment and make sure it fails.
-               let payee = Payee::new(expected_route.last().unwrap().node.get_our_node_id())
-                       .with_features(InvoiceFeatures::known());
-               let route = get_route(&nodes[0].node.get_our_node_id(), &payee, &nodes[0].net_graph_msg_handler.network_graph, None, 100_000, TEST_FINAL_CLTV, &logger, &scorer).unwrap();
+               let params = RouteParameters {
+                       payee: Payee::for_keysend(expected_route.last().unwrap().node.get_our_node_id()),
+                       final_value_msat: 100_000,
+                       final_cltv_expiry_delta: TEST_FINAL_CLTV,
+               };
+               let route = find_route(
+                       &nodes[0].node.get_our_node_id(), &params,
+                       &nodes[0].net_graph_msg_handler.network_graph, None, nodes[0].logger, &scorer
+               ).unwrap();
                nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
                check_added_monitors!(nodes[0], 1);
                let mut events = nodes[0].node.get_and_clear_pending_msg_events();
@@ -6289,7 +6322,10 @@ mod tests {
 
                // To start (2), send a keysend payment but don't claim it.
                let payment_preimage = PaymentPreimage([42; 32]);
-               let route = get_route(&nodes[0].node.get_our_node_id(), &payee, &nodes[0].net_graph_msg_handler.network_graph, None, 100_000, TEST_FINAL_CLTV, &logger, &scorer).unwrap();
+               let route = find_route(
+                       &nodes[0].node.get_our_node_id(), &params,
+                       &nodes[0].net_graph_msg_handler.network_graph, None, nodes[0].logger, &scorer
+               ).unwrap();
                let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
                check_added_monitors!(nodes[0], 1);
                let mut events = nodes[0].node.get_and_clear_pending_msg_events();
@@ -6341,12 +6377,18 @@ mod tests {
                nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() });
 
                let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known());
+               let params = RouteParameters {
+                       payee: Payee::for_keysend(payee_pubkey),
+                       final_value_msat: 10000,
+                       final_cltv_expiry_delta: 40,
+               };
                let network_graph = &nodes[0].net_graph_msg_handler.network_graph;
                let first_hops = nodes[0].node.list_usable_channels();
-               let scorer = Scorer::new(0);
-               let route = get_keysend_route(&payer_pubkey, network_graph, &payee_pubkey,
-                                  Some(&first_hops.iter().collect::<Vec<_>>()), &vec![], 10000, 40,
-                                  nodes[0].logger, &scorer).unwrap();
+               let scorer = Scorer::with_fixed_penalty(0);
+               let route = find_route(
+                       &payer_pubkey, &params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
+                       nodes[0].logger, &scorer
+               ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
                let mismatch_payment_hash = PaymentHash([43; 32]);
@@ -6378,12 +6420,18 @@ mod tests {
                nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() });
 
                let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known());
+               let params = RouteParameters {
+                       payee: Payee::for_keysend(payee_pubkey),
+                       final_value_msat: 10000,
+                       final_cltv_expiry_delta: 40,
+               };
                let network_graph = &nodes[0].net_graph_msg_handler.network_graph;
                let first_hops = nodes[0].node.list_usable_channels();
-               let scorer = Scorer::new(0);
-               let route = get_keysend_route(&payer_pubkey, network_graph, &payee_pubkey,
-                                  Some(&first_hops.iter().collect::<Vec<_>>()), &vec![], 10000, 40,
-                                  nodes[0].logger, &scorer).unwrap();
+               let scorer = Scorer::with_fixed_penalty(0);
+               let route = find_route(
+                       &payer_pubkey, &params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
+                       nodes[0].logger, &scorer
+               ).unwrap();
 
                let test_preimage = PaymentPreimage([42; 32]);
                let test_secret = PaymentSecret([43; 32]);
@@ -6554,7 +6602,7 @@ pub mod bench {
                                let usable_channels = $node_a.list_usable_channels();
                                let payee = Payee::new($node_b.get_our_node_id())
                                        .with_features(InvoiceFeatures::known());
-                               let scorer = Scorer::new(0);
+                               let scorer = Scorer::with_fixed_penalty(0);
                                let route = get_route(&$node_a.get_our_node_id(), &payee, &dummy_graph,
                                        Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap();