mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
renepay: add a helper module json.c
This commit is contained in:
parent
73c6142965
commit
cc00d509b1
2 changed files with 299 additions and 0 deletions
281
plugins/renepay/json.c
Normal file
281
plugins/renepay/json.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
#include <common/json_stream.h>
|
||||
#include <plugins/renepay/json.h>
|
||||
|
||||
/* See if this notification is about one of our flows. */
|
||||
struct routekey *tal_routekey_from_json(const tal_t *ctx, const char *buf,
|
||||
const jsmntok_t *obj)
|
||||
{
|
||||
struct routekey *key = tal(ctx, struct routekey);
|
||||
|
||||
const jsmntok_t *hashtok = json_get_member(buf, obj, "payment_hash");
|
||||
const jsmntok_t *groupidtok = json_get_member(buf, obj, "groupid");
|
||||
const jsmntok_t *partidtok = json_get_member(buf, obj, "partid");
|
||||
|
||||
if (hashtok == NULL || groupidtok == NULL)
|
||||
goto fail;
|
||||
|
||||
if (!json_to_u64(buf, groupidtok, &key->groupid))
|
||||
goto fail;
|
||||
if (!json_to_sha256(buf, hashtok, &key->payment_hash))
|
||||
goto fail;
|
||||
if (partidtok == NULL)
|
||||
key->partid = 0;
|
||||
else if (!json_to_u64(buf, partidtok, &key->partid))
|
||||
goto fail;
|
||||
|
||||
return key;
|
||||
fail:
|
||||
|
||||
return tal_free(key);
|
||||
}
|
||||
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 *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");
|
||||
const jsmntok_t *erridxtok, *msgtok, *failcodetok, *rawmsgtok,
|
||||
*failcodenametok, *errchantok, *errnodetok, *errdirtok;
|
||||
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");
|
||||
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 ||
|
||||
statustok == NULL || statustok->type != JSMN_STRING) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = tal(ctx, struct payment_result);
|
||||
|
||||
if (codetok != NULL)
|
||||
// u32? isn't this an int?
|
||||
// json_to_u32(buffer, codetok, &result->code);
|
||||
json_to_int(buffer, codetok, &result->code);
|
||||
else
|
||||
result->code = 0;
|
||||
|
||||
json_to_u64(buffer, idtok, &result->id);
|
||||
json_to_msat(buffer, senttok, &result->amount_sent);
|
||||
if (json_tok_streq(buffer, statustok, "pending")) {
|
||||
result->status = SENDPAY_PENDING;
|
||||
} else if (json_tok_streq(buffer, statustok, "complete")) {
|
||||
result->status = SENDPAY_COMPLETE;
|
||||
} else if (json_tok_streq(buffer, statustok, "failed")) {
|
||||
result->status = SENDPAY_FAILED;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (preimagetok != NULL) {
|
||||
result->payment_preimage = tal(result, struct preimage);
|
||||
json_to_preimage(buffer, preimagetok, result->payment_preimage);
|
||||
}
|
||||
|
||||
/* Now extract the error details if the error code is not 0 */
|
||||
if (result->code != 0) {
|
||||
erridxtok = json_get_member(buffer, datatok, "erring_index");
|
||||
errnodetok = json_get_member(buffer, datatok, "erring_node");
|
||||
errchantok = json_get_member(buffer, datatok, "erring_channel");
|
||||
errdirtok =
|
||||
json_get_member(buffer, datatok, "erring_direction");
|
||||
failcodetok = json_get_member(buffer, datatok, "failcode");
|
||||
failcodenametok =
|
||||
json_get_member(buffer, datatok, "failcodename");
|
||||
msgtok = json_get_member(buffer, toks, "message");
|
||||
rawmsgtok = json_get_member(buffer, datatok, "raw_message");
|
||||
if (failcodetok == NULL ||
|
||||
failcodetok->type != JSMN_PRIMITIVE ||
|
||||
(failcodenametok != NULL &&
|
||||
failcodenametok->type != JSMN_STRING) ||
|
||||
(erridxtok != NULL && erridxtok->type != JSMN_PRIMITIVE) ||
|
||||
(errnodetok != NULL && errnodetok->type != JSMN_STRING) ||
|
||||
(errchantok != NULL && errchantok->type != JSMN_STRING) ||
|
||||
(errdirtok != NULL && errdirtok->type != JSMN_PRIMITIVE) ||
|
||||
msgtok == NULL || msgtok->type != JSMN_STRING ||
|
||||
(rawmsgtok != NULL && rawmsgtok->type != JSMN_STRING))
|
||||
goto fail;
|
||||
|
||||
if (rawmsgtok != NULL)
|
||||
result->raw_message =
|
||||
json_tok_bin_from_hex(result, buffer, rawmsgtok);
|
||||
else
|
||||
result->raw_message = NULL;
|
||||
|
||||
if (failcodenametok != NULL)
|
||||
result->failcodename =
|
||||
json_strdup(result, buffer, failcodenametok);
|
||||
else
|
||||
result->failcodename = NULL;
|
||||
|
||||
json_to_u32(buffer, failcodetok, &result->failcode);
|
||||
result->message = json_strdup(result, buffer, msgtok);
|
||||
|
||||
if (erridxtok != NULL) {
|
||||
result->erring_index = tal(result, u32);
|
||||
json_to_u32(buffer, erridxtok, result->erring_index);
|
||||
} else {
|
||||
result->erring_index = NULL;
|
||||
}
|
||||
|
||||
if (errdirtok != NULL) {
|
||||
result->erring_direction = tal(result, int);
|
||||
json_to_int(buffer, errdirtok,
|
||||
result->erring_direction);
|
||||
} else {
|
||||
result->erring_direction = NULL;
|
||||
}
|
||||
|
||||
if (errnodetok != NULL) {
|
||||
result->erring_node = tal(result, struct node_id);
|
||||
json_to_node_id(buffer, errnodetok,
|
||||
result->erring_node);
|
||||
} else {
|
||||
result->erring_node = NULL;
|
||||
}
|
||||
|
||||
if (errchantok != NULL) {
|
||||
result->erring_channel =
|
||||
tal(result, struct short_channel_id);
|
||||
json_to_short_channel_id(buffer, errchantok,
|
||||
result->erring_channel);
|
||||
} else {
|
||||
result->erring_channel = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
fail:
|
||||
return tal_free(result);
|
||||
}
|
||||
|
||||
// TODO add verbose option to include more or less details or change the schema,
|
||||
// checkout docs/schema/renepay.schema.json and
|
||||
// docs/schema/renepaystatus.schema.json
|
||||
void json_add_payment(struct json_stream *s, const struct payment *payment)
|
||||
{
|
||||
assert(s);
|
||||
assert(payment);
|
||||
|
||||
if (payment->label != NULL)
|
||||
json_add_string(s, "label", payment->label);
|
||||
if (payment->invstr != NULL)
|
||||
json_add_invstring(s, payment->invstr);
|
||||
|
||||
json_add_amount_msat(s, "amount_msat", payment->amount);
|
||||
json_add_sha256(s, "payment_hash", &payment->payment_hash);
|
||||
json_add_node_id(s, "destination", &payment->destination);
|
||||
|
||||
if (payment->description)
|
||||
json_add_string(s, "description", payment->description);
|
||||
|
||||
json_add_timeabs(s, "created_at", payment->start_time);
|
||||
json_add_u64(s, "groupid", payment->groupid);
|
||||
json_add_u64(s, "parts", payment->next_partid);
|
||||
|
||||
switch (payment->status) {
|
||||
case PAYMENT_SUCCESS:
|
||||
assert(payment->preimage);
|
||||
|
||||
json_add_string(s, "status", "complete");
|
||||
json_add_preimage(s, "payment_preimage", payment->preimage);
|
||||
json_add_amount_msat(s, "amount_sent_msat",
|
||||
payment->total_sent);
|
||||
break;
|
||||
case PAYMENT_FAIL:
|
||||
json_add_string(s, "status", "failed");
|
||||
break;
|
||||
case PAYMENT_PENDING:
|
||||
json_add_string(s, "status", "pending");
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: add more verbose outputs?
|
||||
// json_array_start(s, "notes");
|
||||
// for (size_t i = 0; i < tal_count(payment->paynotes); i++)
|
||||
// json_add_string(s, NULL, payment->paynotes[i]);
|
||||
// json_array_end(s);
|
||||
|
||||
// TODO(eduardo): maybe we should add also:
|
||||
// - payment_secret?
|
||||
// - payment_metadata?
|
||||
// - number of parts?
|
||||
}
|
||||
|
||||
void json_add_route(struct json_stream *js, const struct route *route)
|
||||
{
|
||||
assert(js);
|
||||
assert(route);
|
||||
|
||||
struct payment *payment = route->payment;
|
||||
assert(payment);
|
||||
|
||||
assert(route->hops);
|
||||
const size_t pathlen = tal_count(route->hops);
|
||||
|
||||
json_array_start(js, "route");
|
||||
/* An empty route means a payment to oneself, pathlen=0 */
|
||||
for (size_t j = 0; j < pathlen; j++) {
|
||||
const struct route_hop *hop = &route->hops[j];
|
||||
|
||||
json_object_start(js, NULL);
|
||||
json_add_node_id(js, "id", &hop->node_id);
|
||||
json_add_short_channel_id(js, "channel", hop->scid);
|
||||
json_add_amount_msat(js, "amount_msat", hop->amount);
|
||||
json_add_num(js, "direction", hop->direction);
|
||||
json_add_u32(js, "delay", hop->delay);
|
||||
json_add_string(js, "style", "tlv");
|
||||
json_object_end(js);
|
||||
}
|
||||
json_array_end(js);
|
||||
json_add_sha256(js, "payment_hash", &payment->payment_hash);
|
||||
|
||||
if (payment->payment_secret)
|
||||
json_add_secret(js, "payment_secret", payment->payment_secret);
|
||||
|
||||
/* FIXME: sendpay has a check that we don't total more than
|
||||
* the exact amount, if we're setting partid (i.e. MPP).
|
||||
* However, we always set partid, and we add a shadow amount if
|
||||
* we've only have one part, so we have to use that amount
|
||||
* here.
|
||||
*
|
||||
* The spec was loosened so you are actually allowed
|
||||
* to overpay, so this check is now overzealous. */
|
||||
if (pathlen > 0 &&
|
||||
amount_msat_greater(route_delivers(route), payment->amount)) {
|
||||
json_add_amount_msat(js, "amount_msat", route_delivers(route));
|
||||
} else {
|
||||
json_add_amount_msat(js, "amount_msat", payment->amount);
|
||||
}
|
||||
json_add_u64(js, "partid", route->key.partid);
|
||||
json_add_u64(js, "groupid", route->key.groupid);
|
||||
|
||||
/* FIXME: some of these fields might not be required for all
|
||||
* payment parts. */
|
||||
json_add_string(js, "bolt11", payment->invstr);
|
||||
|
||||
if (payment->payment_metadata)
|
||||
json_add_hex_talarr(js, "payment_metadata",
|
||||
payment->payment_metadata);
|
||||
if (payment->label)
|
||||
json_add_string(js, "label", payment->label);
|
||||
if (payment->description)
|
||||
json_add_string(js, "description", payment->description);
|
||||
|
||||
}
|
18
plugins/renepay/json.h
Normal file
18
plugins/renepay/json.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef LIGHTNING_PLUGINS_RENEPAY_JSON_H
|
||||
#define LIGHTNING_PLUGINS_RENEPAY_JSON_H
|
||||
|
||||
#include <plugins/renepay/payment.h>
|
||||
#include <plugins/renepay/route.h>
|
||||
|
||||
struct routekey *tal_routekey_from_json(const tal_t *ctx, const char *buf,
|
||||
const jsmntok_t *obj);
|
||||
|
||||
struct payment_result *tal_sendpay_result_from_json(const tal_t *ctx,
|
||||
const char *buffer,
|
||||
const jsmntok_t *toks);
|
||||
|
||||
void json_add_payment(struct json_stream *s, const struct payment *payment);
|
||||
|
||||
void json_add_route(struct json_stream *s, const struct route *route);
|
||||
|
||||
#endif /* LIGHTNING_PLUGINS_RENEPAY_JSON_H */
|
Loading…
Add table
Reference in a new issue