From 90ab9325a11dbd785fc0250edb6ee5acc6232795 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 23 Nov 2024 07:33:25 +1030 Subject: [PATCH] xpay: give an additional block "slack" for CLTV values. pay does this, xpay does not. Which means if a block comes in (or you're behind), you get gratuitous failures: ``` def test_xpay_simple(node_factory): l1, l2, l3, l4 = node_factory.get_nodes(4, opts={'may_reconnect': True}) node_factory.join_nodes([l1, l2, l3], wait_for_announce=True) node_factory.join_nodes([l3, l4], announce_channels=False) # BOLT 11, direct peer b11 = l2.rpc.invoice('10000msat', 'test_xpay_simple', 'test_xpay_simple bolt11')['bolt11'] > ret = l1.rpc.xpay(b11) tests/test_xpay.py:148: ... if not isinstance(resp, dict): raise TypeError("Malformed response, response is not a dictionary %s." % resp) elif "error" in resp: > raise RpcError(method, payload, resp['error']) E pyln.client.lightning.RpcError: RPC call failed: method: xpay, payload: ('lnbcrt100n1pn5qu7csp53rp0mfwtfsyyy8gzsggepnxgslyalwvz3jkg9ptmqq452ln2nmgqpp58ak9nmfz9l93r0fpm266ewyjrhurhatrs05nda0r03p82cykp0vsdp9w3jhxazl0pcxz72lwd5k6urvv5sxymmvwscnzxqyjw5qcqp99qxpqysgqa798258yppu2tlfj8herr3zuz0zgux79zvtx6z57cmfzs2wdesmr4nvnkcmyssyu6k64ud54eg0v45c3mcw342jj6uy7tu202p6klrcp6ljc9w',), error: {'code': 203, 'message': "Destination said it doesn't know invoice: incorrect_or_unknown_payment_details"} ``` Signed-off-by: Rusty Russell Changelog-None: xpay is new this release. --- plugins/xpay/xpay.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index a139ed5db..27166cda0 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -777,11 +777,11 @@ static struct command_result *injectpaymentonion_succeeded(struct command *aux_c static void append_blinded_payloads(struct sphinx_path *sp, const struct attempt *attempt, + u32 effective_bheight, size_t path_num) { const struct blinded_path *path = attempt->payment->paths[path_num]; - struct xpay *xpay = xpay_of(attempt->payment->plugin); - u32 final_cltv = attempt->payment->final_cltv + xpay->blockheight; + u32 final_cltv = attempt->payment->final_cltv + effective_bheight; for (size_t i = 0; i < tal_count(path->path); i++) { bool first = (i == 0); @@ -813,7 +813,9 @@ static void append_blinded_payloads(struct sphinx_path *sp, } } -static const u8 *create_onion(const tal_t *ctx, struct attempt *attempt) +static const u8 *create_onion(const tal_t *ctx, + struct attempt *attempt, + u32 effective_bheight) { struct xpay *xpay = xpay_of(attempt->payment->plugin); bool blinded_path = false; @@ -834,7 +836,8 @@ static const u8 *create_onion(const tal_t *ctx, struct attempt *attempt) if (pubkey_eq(&hop->next_node, &xpay->fakenode) && hop->scidd.scid.u64 < tal_count(attempt->payment->paths)) { blinded_path = true; - append_blinded_payloads(sp, attempt, hop->scidd.scid.u64); + append_blinded_payloads(sp, attempt, effective_bheight, + hop->scidd.scid.u64); /* This must be at the end, unless they put the fake nodeid * in a layer, in which case it doesn't matter what we put * in the rest of the onion. */ @@ -842,7 +845,7 @@ static const u8 *create_onion(const tal_t *ctx, struct attempt *attempt) } /* We tell it how much to send *out* */ payload = onion_nonfinal_hop(NULL, &hop->scidd.scid, hop->amount_out, - hop->cltv_value_out + xpay->blockheight); + hop->cltv_value_out + effective_bheight); sphinx_add_hop_has_length(sp, node, take(payload)); node = &hop->next_node; } @@ -853,7 +856,7 @@ static const u8 *create_onion(const tal_t *ctx, struct attempt *attempt) sphinx_add_hop_has_length(sp, node, take(onion_final_hop(NULL, attempt->delivers, - attempt->payment->final_cltv + xpay->blockheight, + attempt->payment->final_cltv + effective_bheight, attempt->payment->full_amount, attempt->payment->payment_secret, attempt->payment->payment_metadata))); @@ -876,8 +879,10 @@ static struct command_result *do_inject(struct command *aux_cmd, struct out_req *req; const u8 *onion; struct xpay *xpay = xpay_of(attempt->payment->plugin); + /* In case a block comes in, we give CLTVs an extra 1. */ + u32 effective_bheight = xpay->blockheight + 1; - onion = create_onion(tmpctx, attempt); + onion = create_onion(tmpctx, attempt, effective_bheight); /* FIXME: Handle this better! */ if (!onion) { payment_failed(aux_cmd, attempt->payment, PAY_UNSPECIFIED_ERROR, @@ -894,7 +899,7 @@ static struct command_result *do_inject(struct command *aux_cmd, json_add_sha256(req->js, "payment_hash", &attempt->payment->payment_hash); /* If no route, its the same as delivery (self-pay) */ json_add_amount_msat(req->js, "amount_msat", initial_sent(attempt)); - json_add_u32(req->js, "cltv_expiry", initial_cltv_delta(attempt) + xpay->blockheight); + json_add_u32(req->js, "cltv_expiry", initial_cltv_delta(attempt) + effective_bheight); json_add_u64(req->js, "partid", attempt->partid); json_add_u64(req->js, "groupid", attempt->payment->group_id); json_add_string(req->js, "invstring", attempt->payment->invstring);