From 90c2a9d5654fea123ecaac12dfb73d5e51d1d558 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 17 Aug 2023 17:11:53 +0930 Subject: [PATCH 1/2] pytest: test that we can pay via routehints even if a 1000-min-htlc channel is in path. Signed-off-by: Rusty Russell --- tests/test_pay.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_pay.py b/tests/test_pay.py index b16a2d7b088e..b2fab1301b27 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -5387,3 +5387,31 @@ def test_listsendpays_crash(node_factory): inv = l1.rpc.invoice(40, "inv", "inv")["bolt11"] l1.rpc.listsendpays('lightning:' + inv) + + +@pytest.mark.xfail(strict=True) +@pytest.mark.developer("updates are delayed without --dev-fast-gossip") +def test_pay_routehint_minhtlc(node_factory, bitcoind): + # l1 -> l2 -> l3 private -> l4 + l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True) + l4 = node_factory.get_node() + + l3.fundchannel(l4, announce_channel=False) + + # l2->l3 required htlc of at least 1sat + scid = only_one(l2.rpc.setchannel(l3.info['id'], htlcmin=1000)['channels'])['short_channel_id'] + + # Make sure l4 knows about l1 + wait_for(lambda: l4.rpc.listnodes(l1.info['id'])['nodes'] != []) + + # And make sure l1 knows that l2->l3 has htlcmin 1000 + wait_for(lambda: l1.rpc.listchannels(scid)['channels'][0]['htlc_minimum_msat'] == Millisatoshi(1000)) + + inv = l4.rpc.invoice(100000, "inv", "inv") + assert only_one(l1.rpc.decodepay(inv['bolt11'])['routes']) + + # You should be able to pay the invoice! + l1.rpc.pay(inv['bolt11']) + + # And you should also be able to getroute (and have it ignore htlc_min/max constraints!) + l1.rpc.getroute(l3.info['id'], amount_msat=0, riskfactor=1) From a867259d4e666f178b764f0d13e4fed8104ffb08 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 17 Aug 2023 19:51:19 +0930 Subject: [PATCH 2/2] pay: don't discard high-htlc_min channels when searching for routehint starts. As side-effect, getroute(0) is special too. Reported-by: MiddleW4y in Discord Fixes: #6577 Changelog-Fixed: `pay` will still use an invoice routehint if path to it doesn't take 1-msat payments. --- common/route.c | 4 +++- doc/lightning-getroute.7.md | 4 +++- plugins/libplugin-pay.c | 6 +++--- tests/test_pay.py | 1 - 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/common/route.c b/common/route.c index f88cb0082ac2..64beb206313d 100644 --- a/common/route.c +++ b/common/route.c @@ -13,7 +13,9 @@ bool route_can_carry_even_disabled(const struct gossmap *map, { if (!gossmap_chan_set(c, dir)) return false; - if (!gossmap_chan_capacity(c, dir, amount)) + /* Amount 0 is a special "ignore min" probe case */ + if (!amount_msat_eq(amount, AMOUNT_MSAT(0)) + && !gossmap_chan_capacity(c, dir, amount)) return false; return true; } diff --git a/doc/lightning-getroute.7.md b/doc/lightning-getroute.7.md index 1b59cde18a9a..ff3777f31d0b 100644 --- a/doc/lightning-getroute.7.md +++ b/doc/lightning-getroute.7.md @@ -17,7 +17,9 @@ arrive at *id* with *cltv*-blocks to spare (default 9). *amount\_msat* is in millisatoshi precision; it can be a whole number, or a whole number ending in *msat* or *sat*, or a number with three decimal places ending in *sat*, or a number with 1 to 11 decimal places ending -in *btc*. +in *btc*. The 0 value is special: it ignores any *htlc\_minimum\_msat* +setting on channels, and simply returns a possible route (if any) which +is useful for simple probing. There are two considerations for how good a route is: how low the fees are, and how long your payment will get stuck in a delayed output if a diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index b4ae81d6c13d..8826c7ff511b 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -2521,7 +2521,7 @@ static struct route_info **filter_routehints(struct gossmap *map, } distance = dijkstra_distance( - dijkstra(tmpctx, map, entrynode, AMOUNT_MSAT(1), 1, + dijkstra(tmpctx, map, entrynode, AMOUNT_MSAT(0), 1, payment_route_can_carry_even_disabled, route_score_cheaper, p), gossmap_node_idx(map, src)); @@ -2763,12 +2763,12 @@ static void routehint_check_reachable(struct payment *p) if (dst == NULL) d->destination_reachable = false; else if (src != NULL) { - dij = dijkstra(tmpctx, gossmap, dst, AMOUNT_MSAT(1000), + dij = dijkstra(tmpctx, gossmap, dst, AMOUNT_MSAT(0), 10 / 1000000.0, payment_route_can_carry_even_disabled, route_score_cheaper, p); r = route_from_dijkstra(tmpctx, gossmap, dij, src, - AMOUNT_MSAT(1000), 0); + AMOUNT_MSAT(0), 0); /* If there was a route the destination is reachable * without routehints. */ diff --git a/tests/test_pay.py b/tests/test_pay.py index b2fab1301b27..a936ce151353 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -5389,7 +5389,6 @@ def test_listsendpays_crash(node_factory): l1.rpc.listsendpays('lightning:' + inv) -@pytest.mark.xfail(strict=True) @pytest.mark.developer("updates are delayed without --dev-fast-gossip") def test_pay_routehint_minhtlc(node_factory, bitcoind): # l1 -> l2 -> l3 private -> l4