From 4ed709f9ec3d76555db2faf747d2a67f72853dc3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 14 Feb 2025 15:22:48 +1030 Subject: [PATCH] xpay: avoid MPP if invoice does not allow it. This is deeply annoying, and we may have to support this properly (using a separate algorithm entirely) if other implementations don't fix their crap. Signed-off-by: Rusty Russell Changelog-Fixed: Plugins: xpay: suppress multi-part payment if invoice doesn't allow it (please, fix your nodes!) --- plugins/xpay/xpay.c | 11 +++++++++++ tests/test_xpay.py | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index b74ecbef6..fca3f6834 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -76,6 +76,8 @@ struct payment { struct amount_msat maxfee; /* Maximum delay on the route we're ok with */ u32 *maxdelay; + /* Do we have to do it all in a single part? */ + bool disable_mpp; /* BOLT11 payment secret (NULL for BOLT12, it uses blinded paths) */ const struct secret *payment_secret; /* BOLT11 payment metadata (NULL for BOLT12, it uses blinded paths) */ @@ -1192,6 +1194,8 @@ static struct command_result *getroutes_for(struct command *aux_cmd, /* Add user-specified layers */ for (size_t i = 0; i < tal_count(payment->layers); i++) json_add_string(req->js, NULL, payment->layers[i]); + if (payment->disable_mpp) + json_add_string(req->js, NULL, "auto.no_mpp_support"); json_array_end(req->js); json_add_amount_msat(req->js, "maxfee_msat", maxfee); json_add_u32(req->js, "final_cltv", payment->final_cltv); @@ -1457,6 +1461,11 @@ preapproveinvoice_succeed(struct command *cmd, payment->unique_id = xpay->counter++; payment->private_layer = tal_fmt(payment, "xpay-%"PRIu64, payment->unique_id); + + /* Now unique_id is set, we can log this message */ + if (payment->disable_mpp) + payment_log(payment, LOG_INFORM, "No MPP support: this is going to be hard to pay"); + return populate_private_layer(cmd, payment); } @@ -1551,6 +1560,7 @@ static struct command_result *json_xpay_core(struct command *cmd, if (payment->payinfos[i]->cltv_expiry_delta > payment->final_cltv) payment->final_cltv = payment->payinfos[i]->cltv_expiry_delta; } + payment->disable_mpp = false; } else { struct bolt11 *b11 = bolt11_decode(tmpctx, payment->invstring, @@ -1586,6 +1596,7 @@ static struct command_result *json_xpay_core(struct command *cmd, else payment->full_amount = *msat; + payment->disable_mpp = !feature_offered(b11->features, OPT_BASIC_MPP); if (amount_msat_is_zero(payment->full_amount)) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Cannot pay bolt11 invoice with zero amount"); diff --git a/tests/test_xpay.py b/tests/test_xpay.py index a9220e3e7..24285d862 100644 --- a/tests/test_xpay.py +++ b/tests/test_xpay.py @@ -621,7 +621,6 @@ def test_xpay_zeroconf(node_factory): l1.rpc.xpay(b12) -@pytest.mark.xfail(strict=True) def test_xpay_no_mpp(node_factory, chainparams): """Suppress mpp, resulting in a single payment part""" l1, l2, l3, l4 = node_factory.get_nodes(4)