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.
This commit is contained in:
Christian Decker
2020-05-14 20:22:40 +02:00
parent 6fb81bf203
commit 4fec969062
2 changed files with 92 additions and 7 deletions

View File

@@ -1,6 +1,7 @@
#include <plugins/libplugin-pay.h>
#include <stdio.h>
#include <bitcoin/preimage.h>
#include <ccan/array_size/array_size.h>
#include <ccan/tal/str/str.h>
#include <common/json_stream.h>
@@ -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)
{
/* 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. */
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. */
p->step = PAYMENT_STEP_FAILED;
payment_continue(p);
return command_still_pending(cmd);
}