diff --git a/contrib/msggen/msggen/schema.json b/contrib/msggen/msggen/schema.json index 0a6125552..e81f2e369 100644 --- a/contrib/msggen/msggen/schema.json +++ b/contrib/msggen/msggen/schema.json @@ -36428,10 +36428,10 @@ }, "response": { "payment_preimage": "paymentpreimgxp1010101010101010101010101010101010101010101010101", - "failed_parts": 0, - "successful_parts": 1, "amount_msat": 10000, - "amount_sent_msat": 10002 + "amount_sent_msat": 10002, + "failed_parts": 0, + "successful_parts": 1 } }, { @@ -36444,10 +36444,10 @@ }, "response": { "payment_preimage": "paymentpreimgxp2020202020202020202020202020202020202020202020202", - "failed_parts": 0, - "successful_parts": 1, "amount_msat": 1000, - "amount_sent_msat": 1000 + "amount_sent_msat": 1000, + "failed_parts": 0, + "successful_parts": 1 } } ] diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index fc713d6e1..1e9d5d014 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -540,8 +540,7 @@ command, so they invoices can also be paid onchain. * **xpay-handle-pay**=*BOOL* [plugin `xpay`, *dynamic*] - Setting this makes `xpay` intercept simply `pay` commands (default `false`). Note that the -response will be different from the normal pay command, however. + Setting this makes `xpay` intercept simply `pay` commands (default `false`). ### Networking options diff --git a/doc/schemas/lightning-xpay.json b/doc/schemas/lightning-xpay.json index 8cdfcc037..4db05c41f 100644 --- a/doc/schemas/lightning-xpay.json +++ b/doc/schemas/lightning-xpay.json @@ -132,10 +132,10 @@ }, "response": { "payment_preimage": "paymentpreimgxp1010101010101010101010101010101010101010101010101", - "failed_parts": 0, - "successful_parts": 1, "amount_msat": 10000, - "amount_sent_msat": 10002 + "amount_sent_msat": 10002, + "failed_parts": 0, + "successful_parts": 1 } }, { @@ -148,10 +148,10 @@ }, "response": { "payment_preimage": "paymentpreimgxp2020202020202020202020202020202020202020202020202", - "failed_parts": 0, - "successful_parts": 1, "amount_msat": 1000, - "amount_sent_msat": 1000 + "amount_sent_msat": 1000, + "failed_parts": 0, + "successful_parts": 1 } } ] diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index 93e53b3a4..78d7984bb 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -111,6 +111,11 @@ struct payment { /* Requests currently outstanding */ struct out_req **requests; + + /* Are we pretending to be "pay"? */ + bool pay_compat; + /* When did we start? */ + struct timeabs start_time; }; /* One step in a path. */ @@ -374,11 +379,19 @@ static void payment_succeeded(struct payment *payment, if (payment->cmd) { js = jsonrpc_stream_success(payment->cmd); json_add_preimage(js, "payment_preimage", preimage); - json_add_u64(js, "failed_parts", payment->num_failures); - json_add_u64(js, "successful_parts", - payment->total_num_attempts - payment->num_failures); json_add_amount_msat(js, "amount_msat", payment->amount); json_add_amount_msat(js, "amount_sent_msat", total_sent(payment, attempt)); + /* Pay's schema expects these fields */ + if (payment->pay_compat) { + json_add_u64(js, "parts", payment->total_num_attempts); + json_add_sha256(js, "payment_hash", &payment->payment_hash); + json_add_string(js, "status", "complete"); + json_add_u64(js, "created_at", (u64)payment->start_time.ts.tv_sec); + } else { + json_add_u64(js, "failed_parts", payment->num_failures); + json_add_u64(js, "successful_parts", + payment->total_num_attempts - payment->num_failures); + } was_pending(command_finished(payment->cmd, js)); payment->cmd = NULL; } @@ -1436,9 +1449,10 @@ preapproveinvoice_succeed(struct command *cmd, return populate_private_layer(cmd, payment); } -static struct command_result *json_xpay(struct command *cmd, - const char *buffer, - const jsmntok_t *params) +static struct command_result *json_xpay_core(struct command *cmd, + const char *buffer, + const jsmntok_t *params, + bool as_pay) { struct xpay *xpay = xpay_of(cmd->plugin); struct amount_msat *msat, *maxfee, *partial; @@ -1468,6 +1482,8 @@ static struct command_result *json_xpay(struct command *cmd, payment->requests = tal_arr(payment, struct out_req *, 0); payment->prior_results = tal_strdup(payment, ""); payment->deadline = timemono_add(time_mono(), time_from_sec(*retryfor)); + payment->start_time = time_now(); + payment->pay_compat = as_pay; if (bolt12_has_prefix(payment->invstring)) { struct gossmap *gossmap = get_gossmap(xpay); @@ -1595,6 +1611,20 @@ static struct command_result *json_xpay(struct command *cmd, return send_outreq(req); } +static struct command_result *json_xpay(struct command *cmd, + const char *buffer, + const jsmntok_t *params) +{ + return json_xpay_core(cmd, buffer, params, false); +} + +static struct command_result *json_xpay_as_pay(struct command *cmd, + const char *buffer, + const jsmntok_t *params) +{ + return json_xpay_core(cmd, buffer, params, true); +} + static struct command_result *getchaininfo_done(struct command *aux_cmd, const char *method, const char *buf, @@ -1727,6 +1757,10 @@ static const struct plugin_command commands[] = { "xpay", json_xpay, }, + { + "xpay-as-pay", + json_xpay_as_pay, + }, }; static struct command_result *handle_block_added(struct command *cmd, @@ -1930,7 +1964,7 @@ static struct command_result *handle_rpc_command(struct command *cmd, json_object_start(response, "replace"); json_add_string(response, "jsonrpc", "2.0"); json_add_tok(response, "id", id_tok, buf); - json_add_string(response, "method", "xpay"); + json_add_string(response, "method", "xpay-as-pay"); json_object_start(response, "params"); json_add_tok(response, "invstring", bolt11, buf); if (amount_msat) diff --git a/tests/test_xpay.py b/tests/test_xpay.py index ec56798fc..f3999f455 100644 --- a/tests/test_xpay.py +++ b/tests/test_xpay.py @@ -368,10 +368,6 @@ def test_xpay_takeover(node_factory, executor): l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True, opts={'xpay-handle-pay': True}) - # xpay does NOT look like pay! - l1.rpc.jsonschemas = {} - l2.rpc.jsonschemas = {} - # Simple bolt11/bolt12 payment. inv = l3.rpc.invoice(100000, "test_xpay_takeover1", "test_xpay_takeover1")['bolt11'] l1.rpc.pay(inv)