From 4fec969062dc2fb9aa2f49d3311022dcec011dcb Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Thu, 14 May 2020 20:22:40 +0200 Subject: [PATCH] paymod: Parse and store the waitsendpay result This is necessary so we can later aggregate across an entire tree of attempts and report success or failure to the RPC caller. --- plugins/libplugin-pay.c | 79 ++++++++++++++++++++++++++++++++++++++--- plugins/libplugin-pay.h | 18 +++++++++- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index 2dff98506..131534dcc 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,7 @@ struct payment *payment_new(tal_t *ctx, struct command *cmd, p->modifiers = mods; p->cmd = cmd; p->start_time = time_now(); - p->partid = partid++; + p->result = NULL; /* Copy over the relevant pieces of information. */ if (parent != NULL) { @@ -209,16 +210,84 @@ fail: return tal_free(resp); } +static struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx, + const char *buffer, + const jsmntok_t *toks) +{ + const jsmntok_t *idtok = json_get_member(buffer, toks, "id"); + const jsmntok_t *hashtok = json_get_member(buffer, toks, "payment_hash"); + const jsmntok_t *partidtok = json_get_member(buffer, toks, "partid"); + const jsmntok_t *senttok = json_get_member(buffer, toks, "amount_sent_msat"); + const jsmntok_t *statustok = json_get_member(buffer, toks, "status"); + const jsmntok_t *preimagetok = json_get_member(buffer, toks, "payment_preimage"); + const jsmntok_t *codetok = json_get_member(buffer, toks, "code"); + const jsmntok_t *datatok = json_get_member(buffer, toks, "data"); + struct payment_result *result; + + /* Check if we have an error and need to descend into data to get + * details. */ + if (codetok != NULL && datatok != NULL) { + idtok = json_get_member(buffer, datatok, "id"); + hashtok = json_get_member(buffer, datatok, "payment_hash"); + partidtok = json_get_member(buffer, datatok, "partid"); + senttok = json_get_member(buffer, datatok, "amount_sent_msat"); + statustok = json_get_member(buffer, datatok, "status"); + } + + /* Initial sanity checks, all these fields must exist. */ + if (idtok == NULL || idtok->type != JSMN_PRIMITIVE || + hashtok == NULL || hashtok->type != JSMN_STRING || + senttok == NULL || senttok->type != JSMN_STRING || + statustok == NULL || statustok->type != JSMN_STRING) { + return NULL; + } + + result = tal(ctx, struct payment_result); + + json_to_u64(buffer, idtok, &result->id); + json_to_u32(buffer, partidtok, &result->partid); + /* TODO Fetch the payment_hash here */ + json_to_msat(buffer, senttok, &result->amount_sent); + + if (json_tok_streq(buffer, statustok, "pending")) { + result->state = PAYMENT_PENDING; + } else if (json_tok_streq(buffer, statustok, "complete")) { + result->state = PAYMENT_COMPLETE; + } else if (json_tok_streq(buffer, statustok, "failed")) { + result->state = PAYMENT_FAILED; + } else { + goto fail; + } + + if (preimagetok != NULL) { + result->payment_preimage = tal(result, struct preimage); + json_to_preimage(buffer, preimagetok, result->payment_preimage); + } + + return result; +fail: + return tal_free(result); +} + static struct command_result * payment_waitsendpay_finished(struct command *cmd, const char *buffer, const jsmntok_t *toks, struct payment *p) { + p->result = tal_sendpay_result_from_json(p, buffer, toks); + + if (p->result == NULL) + plugin_err( + p->plugin, "Unable to parse `waitsendpay` result: %.*s", + json_tok_full_len(toks), json_tok_full(buffer, toks)); + + if (p->result->state == PAYMENT_COMPLETE) + p->step = PAYMENT_STEP_SUCCESS; + else + p->step = PAYMENT_STEP_FAILED; + /* TODO examine the failure and eventually stash exclusions that we - * learned in the payment, so sub-payments can avoid them. We also - * need to store the waitsendpay result so we can mock an overall - * waitsendpay for the root later. */ + * learned in the payment, so sub-payments can avoid them. */ - p->step = PAYMENT_STEP_FAILED; payment_continue(p); return command_still_pending(cmd); } diff --git a/plugins/libplugin-pay.h b/plugins/libplugin-pay.h index c3e1e0139..c8921a709 100644 --- a/plugins/libplugin-pay.h +++ b/plugins/libplugin-pay.h @@ -46,9 +46,23 @@ struct createonion_response { struct secret *shared_secrets; }; +/* States returned by listsendpays, waitsendpay, etc. */ +enum payment_result_state { + PAYMENT_PENDING, + PAYMENT_COMPLETE, + PAYMENT_FAILED, +}; + /* A parsed version of the possible outcomes that a sendpay / payment may - * result in. */ + * result in. It excludes the redundant fields such as payment_hash and partid + * which are already present in the `struct payment` itself. */ struct payment_result { + /* DB internal id */ + u64 id; + u32 partid; + enum payment_result_state state; + struct amount_msat amount_sent; + struct preimage *payment_preimage; }; /* Relevant information about a local channel so we can exclude them early. */ @@ -142,6 +156,8 @@ struct payment { struct payment_modifier **modifiers; void **modifier_data; int current_modifier; + + struct payment_result *result; }; struct payment_modifier {