From 3a35dd34ac069de7c89f51b7f20f61aaa1e599bb Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Fri, 29 May 2020 15:25:00 +0200 Subject: [PATCH] paymod: Add the contents of paystatus This proved to be rather difficult given the tight coupling of the old structs and the output of the command. --- plugins/libplugin-pay.c | 30 ++++++++++++ plugins/pay.c | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index 9c1c096a8..a9f34fcf6 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -473,6 +473,34 @@ static void channel_hints_update(struct payment *root, tal_arr_expand(&root->channel_hints, hint); } +/* Try to infer the erring_node, erring_channel and erring_direction from what + * we know, but don't override the values that are returned by `waitsendpay`. */ +static void payment_result_infer(struct route_hop *route, + struct payment_result *r) +{ + int i, len = tal_count(route); + if (r->code == 0 || r->erring_index == NULL || route == NULL) + return; + + i = *r->erring_index; + assert(i <= len); + + if (r->erring_node == NULL) + r->erring_node = &route[i-1].nodeid; + + /* The above assert was enough for the erring_node, but might be off + * by one on channel and direction, in case the destination failed on + * us. */ + if (i == len) + return; + + if (r->erring_channel == NULL) + r->erring_channel = &route[i].channel_id; + + if (r->erring_direction == NULL) + r->erring_direction = &route[i].direction; +} + static struct command_result * payment_waitsendpay_finished(struct command *cmd, const char *buffer, const jsmntok_t *toks, struct payment *p) @@ -482,6 +510,7 @@ payment_waitsendpay_finished(struct command *cmd, const char *buffer, assert(p->route != NULL); p->result = tal_sendpay_result_from_json(p, buffer, toks); + payment_result_infer(p->route, p->result); if (p->result == NULL) plugin_err( @@ -490,6 +519,7 @@ payment_waitsendpay_finished(struct command *cmd, const char *buffer, if (p->result->state == PAYMENT_COMPLETE) { p->step = PAYMENT_STEP_SUCCESS; + p->end_time = time_now(); payment_continue(p); return command_still_pending(cmd); } diff --git a/plugins/pay.c b/plugins/pay.c index e34a63325..066d6f0f5 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -1453,6 +1453,77 @@ static void add_attempt(struct json_stream *ret, json_object_end(ret); } +static void json_add_sendpay_result(struct json_stream *s, const struct payment_result *r) +{ + if (r->code != 0) { + /* This is a failure */ + json_add_string(s, "message", r->message); + json_add_u32(s, "code", r->code); + + json_object_start(s, "data"); + json_add_u32(s, "id", r->id); + json_add_hex(s, "raw_message", r->raw_message, tal_bytelen(r->raw_message)); + json_add_num(s, "failcode", r->failcode); + json_add_string(s, "failcodename", r->failcodename); + + if (r->erring_index) + json_add_num(s, "erring_index", *r->erring_index); + + if (r->erring_node) + json_add_node_id(s, "erring_node", r->erring_node); + + if (r->erring_channel) + json_add_short_channel_id(s, "erring_channel", + r->erring_channel); + + if (r->erring_direction) + json_add_num(s, "erring_direction", + *r->erring_direction); + if (r->erring_node) + json_add_node_id(s, "erring_node", r->erring_node); + json_object_end(s); + } else { + /* This is a success */ + json_add_u32(s, "id", r->id); + json_add_preimage(s, "payment_preimage", r->payment_preimage); + } + +} + +static void paystatus_add_payment(struct json_stream *s, const struct payment *p) +{ + char timestr[UTC_TIMELEN]; + + utc_timestring(&p->start_time, timestr); + + json_object_start(s, NULL); + json_add_string(s, "start_time", timestr); + json_add_u64(s, "age_in_seconds", + time_to_sec(time_between(time_now(), p->start_time))); + + /* Any final state will have an end time. */ + if (p->step >= PAYMENT_STEP_SPLIT) { + utc_timestring(&p->end_time, timestr); + json_add_string(s, "end_time", timestr); + } + + /* TODO Add routehint. */ + /* TODO Add route details */ + + if (p->result != NULL) { + if (p->step == PAYMENT_STEP_SUCCESS) + json_object_start(s, "success"); + else + json_object_start(s, "failure"); + json_add_sendpay_result(s, p->result); + json_object_end(s); + } + + json_object_end(s); + for (size_t i = 0; i < tal_count(p->children); i++) + paystatus_add_payment(s, p->children[i]); +} + static struct command_result *json_paystatus(struct command *cmd, const char *buf, const jsmntok_t *params) @@ -1460,6 +1531,7 @@ static struct command_result *json_paystatus(struct command *cmd, struct pay_status *ps; const char *b11str; struct json_stream *ret; + struct payment *p; if (!param(cmd, buf, params, p_opt("bolt11", param_string, &b11str), @@ -1470,6 +1542,7 @@ static struct command_result *json_paystatus(struct command *cmd, json_array_start(ret, "pay"); /* FIXME: Index by bolt11 string! */ + /* TODO(cdecker) Remove once we migrated to `pay` with modifiers. */ list_for_each(&pay_status, ps, list) { if (b11str && !streq(b11str, ps->bolt11)) continue; @@ -1499,6 +1572,33 @@ static struct command_result *json_paystatus(struct command *cmd, json_array_end(ret); json_object_end(ret); } + + list_for_each(&payments, p, list) { + assert(p->parent == NULL); + if (b11str && !streq(b11str, p->bolt11)) + continue; + + json_object_start(ret, NULL); + if (p->bolt11) + json_add_string(ret, "bolt11", p->bolt11); + json_add_amount_msat_only(ret, "amount_msat", p->amount); + json_add_string( + ret, "amount_msat", + type_to_string(tmpctx, struct amount_msat, &p->amount)); + + json_add_node_id(ret, "destination", p->destination); + + /* TODO(cdecker) Add label in once we track labels. */ + /* TODO(cdecker) Add routehint_modifications in once we track + * them. */ + /* TODO(cdecker) Add shadow route once we support it. */ + + /* If it's in listpeers right now, this can be 0 */ + json_array_start(ret, "attempts"); + paystatus_add_payment(ret, p); + json_array_end(ret); + json_object_end(ret); + } json_array_end(ret); return command_finished(cmd, ret);