Try to overpay the recipient if we fail to find a path at all
authorMatt Corallo <git@bluematt.me>
Tue, 26 Sep 2023 21:58:53 +0000 (21:58 +0000)
committerMatt Corallo <git@bluematt.me>
Thu, 28 Sep 2023 20:39:36 +0000 (20:39 +0000)
Previously we'd only try to overpay if we managed to find a path
to the recipient which was sufficient. However, if we fail to find
any path to the recipient at all we should still retry overpaying
the recipient. Ultimately we should be silling to pay whatever
reasonable performance penalty if the alternative is not finding a
path at all, which we do here.

lightning/src/routing/router.rs

index 1c51bb985e94e28bc807baa55f87678302c25faf..bca681dfc9b32f5760d3d9584ca65d802cd29381 100644 (file)
@@ -2454,6 +2454,9 @@ where L::Target: Logger {
                // because we deterministically terminated the search due to low liquidity.
                if !found_new_path && channel_saturation_pow_half != 0 {
                        channel_saturation_pow_half = 0;
+               } else if !found_new_path && hit_minimum_limit && already_collected_value_msat < final_value_msat && path_value_msat != recommended_value_msat {
+                       log_trace!(logger, "Failed to collect enough value, but running again to collect extra paths with a potentially higher limit.");
+                       path_value_msat = recommended_value_msat;
                } else if already_collected_value_msat >= recommended_value_msat || !found_new_path {
                        log_trace!(logger, "Have now collected {} msat (seeking {} msat) in paths. Last path loop {} a new path.",
                                already_collected_value_msat, recommended_value_msat, if found_new_path { "found" } else { "did not find" });
@@ -3223,6 +3226,56 @@ mod tests {
                assert_eq!(fees, 5_000);
        }
 
+       #[test]
+       fn htlc_minimum_recipient_overpay_test() {
+               let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
+               let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
+               let config = UserConfig::default();
+               let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
+               let scorer = ln_test_utils::TestScorer::new();
+               let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+               let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+               // Route to node2 over a single path which requires overpaying the recipient themselves.
+
+               // First disable all paths except the us -> node1 -> node2 path
+               update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate {
+                       chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+                       short_channel_id: 13,
+                       timestamp: 2,
+                       flags: 3,
+                       cltv_expiry_delta: 0,
+                       htlc_minimum_msat: 0,
+                       htlc_maximum_msat: 0,
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       excess_data: Vec::new()
+               });
+
+               // Set channel 4 to free but with a high htlc_minimum_msat
+               update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
+                       chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+                       short_channel_id: 4,
+                       timestamp: 2,
+                       flags: 0,
+                       cltv_expiry_delta: 0,
+                       htlc_minimum_msat: 15_000,
+                       htlc_maximum_msat: MAX_VALUE_MSAT,
+                       fee_base_msat: 0,
+                       fee_proportional_millionths: 0,
+                       excess_data: Vec::new()
+               });
+
+               // Now check that we'll find a path if the htlc_minimum is overrun substantially.
+               let mut route_params = RouteParameters::from_payment_params_and_value(
+                       payment_params.clone(), 5_000);
+               // TODO: This can even overrun the fee limit set by the recipient!
+               route_params.max_total_routing_fee_msat = Some(9_999);
+               let route = get_route(&our_id, &route_params, &network_graph.read_only(), None,
+                       Arc::clone(&logger), &scorer, &Default::default(), &random_seed_bytes).unwrap();
+               assert_eq!(route.get_total_fees(), 10_000);
+       }
+
        #[test]
        fn disable_channels_test() {
                let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();