Skip to content

Commit 73147da

Browse files
committed
xpay: restrict maxparts to 6 for non-public nodes, but remove it if we can't route.
This attempts to solve a problem we have with Phoenix clients: This payment has been split in two many parts by the sender: 31 parts vs max 6 parts allowed for on-the-fly funding. The problem is that we don't have any way in bolt11 or bolt12 to specify the maximum number of HTLCs. As a workaround, we start by restricting askrene to 6 parts if the node is not openly reachable, and if it struggles, we remove the restriction. This would work much better if askrene handled maxparts more completely! See-Also: #8331 Changelog-Fixed: `xpay` will not try to send too many HTLCs through unknown channels (6, as that is Phoenix's limit) unless it has no choice Signed-off-by: Rusty Russell <[email protected]>
1 parent 145af08 commit 73147da

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

plugins/xpay/xpay.c

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ struct payment {
8585
struct amount_msat maxfee;
8686
/* Maximum delay on the route we're ok with */
8787
u32 maxdelay;
88-
/* Maximum number of payment routes that can be pending. */
88+
/* If non-zero: maximum number of payment routes that can be pending. */
8989
u32 maxparts;
9090
/* Do we have to do it all in a single part? */
9191
bool disable_mpp;
@@ -181,7 +181,6 @@ static struct command_result *xpay_core(struct command *cmd,
181181
u32 retryfor,
182182
const struct amount_msat *partial,
183183
u32 maxdelay,
184-
u32 dev_maxparts,
185184
bool as_pay);
186185

187186
/* Wrapper for pending commands (ignores return) */
@@ -1319,6 +1318,16 @@ static struct command_result *getroutes_done_err(struct command *aux_cmd,
13191318
msg = json_strdup(tmpctx, buf, json_get_member(buf, error, "message"));
13201319
json_to_int(buf, json_get_member(buf, error, "code"), &code);
13211320

1321+
/* If we were restricting the number of parts, we remove that
1322+
* restriction and try again. */
1323+
if (payment->maxparts) {
1324+
payment_log(payment, LOG_INFORM,
1325+
"getroute failed with maxparts=%u, so retrying without that restriction",
1326+
payment->maxparts);
1327+
payment->maxparts = 0;
1328+
return getroutes_for(aux_cmd, payment, payment->amount_being_routed);
1329+
}
1330+
13221331
/* Simple case: failed immediately. */
13231332
if (payment->total_num_attempts == 0) {
13241333
payment_give_up(aux_cmd, payment, code, "Failed: %s", msg);
@@ -1380,7 +1389,6 @@ static struct command_result *getroutes_for(struct command *aux_cmd,
13801389
struct out_req *req;
13811390
const struct pubkey *dst;
13821391
struct amount_msat maxfee;
1383-
size_t count_pending;
13841392

13851393
/* I would normally assert here, but we have reports of this happening... */
13861394
if (amount_msat_is_zero(deliver)) {
@@ -1463,9 +1471,11 @@ static struct command_result *getroutes_for(struct command *aux_cmd,
14631471
json_add_amount_msat(req->js, "maxfee_msat", maxfee);
14641472
json_add_u32(req->js, "final_cltv", payment->final_cltv);
14651473
json_add_u32(req->js, "maxdelay", payment->maxdelay);
1466-
count_pending = count_current_attempts(payment);
1467-
assert(payment->maxparts > count_pending);
1468-
json_add_u32(req->js, "maxparts", payment->maxparts - count_pending);
1474+
if (payment->maxparts) {
1475+
size_t count_pending = count_current_attempts(payment);
1476+
assert(payment->maxparts > count_pending);
1477+
json_add_u32(req->js, "maxparts", payment->maxparts - count_pending);
1478+
}
14691479

14701480
return send_payment_req(aux_cmd, payment, req);
14711481
}
@@ -1776,7 +1786,7 @@ struct xpay_params {
17761786
struct amount_msat *msat, *maxfee, *partial;
17771787
const char **layers;
17781788
unsigned int retryfor;
1779-
u32 maxdelay, dev_maxparts;
1789+
u32 maxdelay;
17801790
const char *bip353;
17811791
};
17821792

@@ -1793,7 +1803,7 @@ invoice_fetched(struct command *cmd,
17931803
return xpay_core(cmd, take(to_canonical_invstr(NULL, take(inv))),
17941804
NULL, params->maxfee, params->layers,
17951805
params->retryfor, params->partial, params->maxdelay,
1796-
params->dev_maxparts, false);
1806+
false);
17971807
}
17981808

17991809
static struct command_result *
@@ -1854,7 +1864,7 @@ static struct command_result *json_xpay_params(struct command *cmd,
18541864
struct amount_msat *msat, *maxfee, *partial;
18551865
const char *invstring;
18561866
const char **layers;
1857-
u32 *maxdelay, *maxparts;
1867+
u32 *maxdelay;
18581868
unsigned int *retryfor;
18591869
struct out_req *req;
18601870
struct xpay_params *xparams;
@@ -1867,14 +1877,9 @@ static struct command_result *json_xpay_params(struct command *cmd,
18671877
p_opt_def("retry_for", param_number, &retryfor, 60),
18681878
p_opt("partial_msat", param_msat, &partial),
18691879
p_opt_def("maxdelay", param_u32, &maxdelay, 2016),
1870-
p_opt_dev("dev_maxparts", param_u32, &maxparts, 100),
18711880
NULL))
18721881
return command_param_failed();
18731882

1874-
if (*maxparts == 0)
1875-
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
1876-
"maxparts cannot be zero");
1877-
18781883
/* Is this a one-shot vibe payment? Kids these days! */
18791884
if (!as_pay && bolt12_has_offer_prefix(invstring)) {
18801885
struct command_result *ret;
@@ -1893,7 +1898,6 @@ static struct command_result *json_xpay_params(struct command *cmd,
18931898
xparams->layers = layers;
18941899
xparams->retryfor = *retryfor;
18951900
xparams->maxdelay = *maxdelay;
1896-
xparams->dev_maxparts = *maxparts;
18971901
xparams->bip353 = NULL;
18981902

18991903
return do_fetchinvoice(cmd, invstring, xparams);
@@ -1908,7 +1912,6 @@ static struct command_result *json_xpay_params(struct command *cmd,
19081912
xparams->layers = layers;
19091913
xparams->retryfor = *retryfor;
19101914
xparams->maxdelay = *maxdelay;
1911-
xparams->dev_maxparts = *maxparts;
19121915
xparams->bip353 = invstring;
19131916

19141917
req = jsonrpc_request_start(cmd, "fetchbip353",
@@ -1919,7 +1922,7 @@ static struct command_result *json_xpay_params(struct command *cmd,
19191922
}
19201923

19211924
return xpay_core(cmd, invstring,
1922-
msat, maxfee, layers, *retryfor, partial, *maxdelay, *maxparts,
1925+
msat, maxfee, layers, *retryfor, partial, *maxdelay,
19231926
as_pay);
19241927
}
19251928

@@ -1931,11 +1934,12 @@ static struct command_result *xpay_core(struct command *cmd,
19311934
u32 retryfor,
19321935
const struct amount_msat *partial,
19331936
u32 maxdelay,
1934-
u32 dev_maxparts,
19351937
bool as_pay)
19361938
{
19371939
struct payment *payment = tal(cmd, struct payment);
19381940
struct xpay *xpay = xpay_of(cmd->plugin);
1941+
struct gossmap *gossmap = get_gossmap(xpay);
1942+
struct node_id dstid;
19391943
u64 now, invexpiry;
19401944
struct out_req *req;
19411945
char *err;
@@ -1959,10 +1963,8 @@ static struct command_result *xpay_core(struct command *cmd,
19591963
else
19601964
payment->layers = NULL;
19611965
payment->maxdelay = maxdelay;
1962-
payment->maxparts = dev_maxparts;
19631966

19641967
if (bolt12_has_prefix(payment->invstring)) {
1965-
struct gossmap *gossmap = get_gossmap(xpay);
19661968
struct tlv_invoice *b12inv
19671969
= invoice_decode(tmpctx, payment->invstring,
19681970
strlen(payment->invstring),
@@ -2088,6 +2090,15 @@ static struct command_result *xpay_core(struct command *cmd,
20882090
} else
20892091
payment->maxfee = *maxfee;
20902092

2093+
/* If we are using an unannounced channel, we assume we can
2094+
* only do 6 HTLCs at a time. This is currently true for
2095+
* Phoenix, which is a large and significant node. */
2096+
node_id_from_pubkey(&dstid, &payment->destination);
2097+
if (!gossmap_find_node(gossmap, &dstid))
2098+
payment->maxparts = 6;
2099+
else
2100+
payment->maxparts = 0;
2101+
20912102
/* Now preapprove, then start payment. */
20922103
if (command_check_only(cmd)) {
20932104
req = jsonrpc_request_start(cmd, "check",

tests/test_xpay.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,6 @@ def test_xpay_bip353(node_factory):
10201020
l2.rpc.xpay('[email protected]', 100)
10211021

10221022

1023-
@pytest.mark.xfail(strict=True)
10241023
def test_xpay_limited_max_accepted_htlcs(node_factory):
10251024
"""xpay should try to reduce flows to 6 if there is an unannounced channel, and only try more if that fails"""
10261025
CHANNEL_SIZE_SATS = 10**6
@@ -1047,6 +1046,9 @@ def test_xpay_limited_max_accepted_htlcs(node_factory):
10471046
# 7 flows.
10481047
l3.daemon.wait_for_log('Final answer has 7 flows')
10491048

1049+
# Make sure xpay has completely finished!
1050+
wait_for(lambda: l3.rpc.askrene_listreservations() == {'reservations': []})
1051+
10501052
# If we have a routehint, it will squeeze into 6.
10511053
inv2 = l2.rpc.invoice(f"{CHANNEL_SIZE_SATS * 5}sat",
10521054
'test_xpay_limited_max_accepted_htlcs',
@@ -1058,13 +1060,16 @@ def test_xpay_limited_max_accepted_htlcs(node_factory):
10581060
# 6 flows.
10591061
l3.daemon.wait_for_log('Final answer has 6 flows')
10601062

1061-
# If we force it, it will use more flows.
1063+
# Make sure xpay has completely finished!
1064+
wait_for(lambda: l3.rpc.askrene_listreservations() == {'reservations': []})
1065+
1066+
# If we force it, it will use more flows. And fail on 7th part!
10621067
inv2 = l2.rpc.invoice(f"{CHANNEL_SIZE_SATS * 6}sat",
10631068
'test_xpay_limited_max_accepted_htlcs2',
10641069
'test_xpay_limited_max_accepted_htlcs2')['bolt11']
1065-
l2.rpc.delinvoice('test_xpay_limited_max_accepted_htlcs2', 'unpaid')
10661070
with pytest.raises(RpcError, match="We got temporary_channel_failure"):
10671071
l3.rpc.xpay(inv2)
1072+
l3.daemon.wait_for_log('Final answer has 7 flows')
10681073

10691074

10701075
def test_xpay_blockheight_mismatch(node_factory, bitcoind, executor):

0 commit comments

Comments
 (0)