2016-09-06 09:17:49 +02:00
|
|
|
#include "invoice.h"
|
2017-11-22 01:25:39 +01:00
|
|
|
#include <bitcoin/address.h>
|
|
|
|
#include <bitcoin/base58.h>
|
|
|
|
#include <bitcoin/script.h>
|
2019-04-10 06:58:24 +02:00
|
|
|
#include <ccan/array_size/array_size.h>
|
2019-06-12 02:38:54 +02:00
|
|
|
#include <ccan/json_escape/json_escape.h>
|
2016-09-06 09:17:49 +02:00
|
|
|
#include <ccan/str/hex/hex.h>
|
|
|
|
#include <ccan/tal/str/str.h>
|
2019-02-21 01:45:57 +01:00
|
|
|
#include <common/amount.h>
|
2017-11-22 01:25:39 +01:00
|
|
|
#include <common/bech32.h>
|
|
|
|
#include <common/bolt11.h>
|
2020-01-31 06:40:26 +01:00
|
|
|
#include <common/configdir.h>
|
2019-11-23 01:19:23 +01:00
|
|
|
#include <common/features.h>
|
2018-12-08 01:39:28 +01:00
|
|
|
#include <common/json_command.h>
|
2019-01-15 05:00:27 +01:00
|
|
|
#include <common/json_helpers.h>
|
2018-12-08 01:39:28 +01:00
|
|
|
#include <common/jsonrpc_errors.h>
|
2019-04-10 06:58:24 +02:00
|
|
|
#include <common/overflows.h>
|
2018-12-08 01:39:28 +01:00
|
|
|
#include <common/param.h>
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
#include <common/pseudorand.h>
|
2020-01-28 02:30:00 +01:00
|
|
|
#include <common/timeout.h>
|
2017-08-28 18:02:01 +02:00
|
|
|
#include <common/utils.h>
|
2017-11-22 01:25:39 +01:00
|
|
|
#include <errno.h>
|
2020-08-25 04:05:45 +02:00
|
|
|
#include <gossipd/gossipd_wiregen.h>
|
2020-08-25 03:55:38 +02:00
|
|
|
#include <hsmd/hsmd_wiregen.h>
|
2017-10-05 23:29:56 +02:00
|
|
|
#include <inttypes.h>
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
#include <lightningd/channel.h>
|
2017-11-22 01:25:39 +01:00
|
|
|
#include <lightningd/hsm_control.h>
|
2019-07-21 13:39:15 +02:00
|
|
|
#include <lightningd/json.h>
|
|
|
|
#include <lightningd/jsonrpc.h>
|
|
|
|
#include <lightningd/lightningd.h>
|
2017-10-05 23:29:56 +02:00
|
|
|
#include <lightningd/log.h>
|
2019-07-21 13:39:15 +02:00
|
|
|
#include <lightningd/notification.h>
|
2018-01-17 04:04:29 +01:00
|
|
|
#include <lightningd/options.h>
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
#include <lightningd/peer_control.h>
|
2019-04-11 02:08:55 +02:00
|
|
|
#include <lightningd/peer_htlcs.h>
|
2019-04-11 02:10:27 +02:00
|
|
|
#include <lightningd/plugin_hook.h>
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
#include <lightningd/subd.h>
|
2016-09-06 09:17:49 +02:00
|
|
|
#include <sodium/randombytes.h>
|
2017-11-22 01:25:39 +01:00
|
|
|
#include <wire/wire_sync.h>
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-02-20 02:07:30 +01:00
|
|
|
static const char *invoice_status_str(const struct invoice_details *inv)
|
2018-01-17 04:04:29 +01:00
|
|
|
{
|
|
|
|
if (inv->state == PAID)
|
|
|
|
return "paid";
|
2018-01-23 02:02:10 +01:00
|
|
|
if (inv->state == EXPIRED)
|
2018-01-17 04:04:29 +01:00
|
|
|
return "expired";
|
|
|
|
return "unpaid";
|
|
|
|
}
|
|
|
|
|
2018-10-19 03:17:49 +02:00
|
|
|
static void json_add_invoice(struct json_stream *response,
|
2018-07-29 04:08:29 +02:00
|
|
|
const struct invoice_details *inv)
|
2018-01-13 12:14:13 +01:00
|
|
|
{
|
2018-03-26 02:08:16 +02:00
|
|
|
json_add_escaped_string(response, "label", inv->label);
|
2018-02-28 17:26:58 +01:00
|
|
|
json_add_string(response, "bolt11", inv->bolt11);
|
2019-08-10 10:39:04 +02:00
|
|
|
json_add_sha256(response, "payment_hash", &inv->rhash);
|
2019-02-21 04:45:55 +01:00
|
|
|
if (inv->msat)
|
2019-05-20 07:07:40 +02:00
|
|
|
json_add_amount_msat_compat(response, *inv->msat,
|
|
|
|
"msatoshi", "amount_msat");
|
2018-07-29 04:08:29 +02:00
|
|
|
json_add_string(response, "status", invoice_status_str(inv));
|
2018-01-13 12:19:33 +01:00
|
|
|
if (inv->state == PAID) {
|
2018-01-13 12:14:13 +01:00
|
|
|
json_add_u64(response, "pay_index", inv->pay_index);
|
2019-05-20 07:07:40 +02:00
|
|
|
json_add_amount_msat_compat(response, inv->received,
|
|
|
|
"msatoshi_received",
|
|
|
|
"amount_received_msat");
|
2018-01-19 10:53:24 +01:00
|
|
|
json_add_u64(response, "paid_at", inv->paid_timestamp);
|
2019-11-26 02:48:03 +01:00
|
|
|
json_add_preimage(response, "payment_preimage", &inv->r);
|
2018-01-13 12:19:33 +01:00
|
|
|
}
|
2018-07-24 20:56:21 +02:00
|
|
|
if (inv->description)
|
|
|
|
json_add_string(response, "description", inv->description);
|
|
|
|
|
2018-01-19 10:53:24 +01:00
|
|
|
json_add_u64(response, "expires_at", inv->expiry_time);
|
2018-01-13 12:14:13 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *tell_waiter(struct command *cmd,
|
|
|
|
const struct invoice *inv)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2018-10-19 03:17:49 +02:00
|
|
|
struct json_stream *response;
|
2018-07-27 12:57:02 +02:00
|
|
|
const struct invoice_details *details;
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-07-27 12:57:02 +02:00
|
|
|
details = wallet_invoice_details(cmd, cmd->ld->wallet, *inv);
|
2018-10-19 03:17:48 +02:00
|
|
|
if (details->state == PAID) {
|
|
|
|
response = json_stream_success(cmd);
|
|
|
|
json_add_invoice(response, details);
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_success(cmd, response);
|
2018-10-19 03:17:48 +02:00
|
|
|
} else {
|
2020-01-26 13:52:29 +01:00
|
|
|
response = json_stream_fail(cmd, INVOICE_EXPIRED_DURING_WAIT,
|
2018-10-19 03:17:48 +02:00
|
|
|
"invoice expired during wait");
|
|
|
|
json_add_invoice(response, details);
|
2019-06-12 02:38:54 +02:00
|
|
|
json_object_end(response);
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_failed(cmd, response);
|
2018-05-24 23:40:18 +02:00
|
|
|
}
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
2018-10-19 03:17:48 +02:00
|
|
|
|
2018-01-14 15:15:30 +01:00
|
|
|
static void tell_waiter_deleted(struct command *cmd)
|
2017-12-27 13:55:22 +01:00
|
|
|
{
|
2018-12-16 05:53:06 +01:00
|
|
|
was_pending(command_fail(cmd, LIGHTNINGD,
|
|
|
|
"Invoice deleted during wait"));
|
2017-12-27 13:55:22 +01:00
|
|
|
}
|
2018-01-14 15:15:30 +01:00
|
|
|
static void wait_on_invoice(const struct invoice *invoice, void *cmd)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2018-01-14 15:15:30 +01:00
|
|
|
if (invoice)
|
|
|
|
tell_waiter((struct command *) cmd, invoice);
|
|
|
|
else
|
|
|
|
tell_waiter_deleted((struct command *) cmd);
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
2020-01-28 02:30:00 +01:00
|
|
|
static void wait_timed_out(struct command *cmd)
|
|
|
|
{
|
|
|
|
was_pending(command_fail(cmd, INVOICE_WAIT_TIMED_OUT,
|
|
|
|
"Timed out while waiting "
|
|
|
|
"for invoice to be paid"));
|
|
|
|
}
|
2016-11-11 00:02:04 +01:00
|
|
|
|
2019-11-23 01:19:23 +01:00
|
|
|
/* We derive invoice secret using 1-way function from payment_preimage
|
|
|
|
* (just a different one from the payment_hash!) */
|
|
|
|
static void invoice_secret(const struct preimage *payment_preimage,
|
|
|
|
struct secret *payment_secret)
|
|
|
|
{
|
|
|
|
struct preimage modified;
|
|
|
|
struct sha256 secret;
|
|
|
|
|
|
|
|
modified = *payment_preimage;
|
|
|
|
modified.r[0] ^= 1;
|
|
|
|
|
|
|
|
sha256(&secret, modified.r,
|
|
|
|
ARRAY_SIZE(modified.r) * sizeof(*modified.r));
|
|
|
|
BUILD_ASSERT(sizeof(secret.u.u8) == sizeof(payment_secret->data));
|
|
|
|
memcpy(payment_secret->data, secret.u.u8, sizeof(secret.u.u8));
|
|
|
|
}
|
|
|
|
|
2019-04-11 02:10:27 +02:00
|
|
|
struct invoice_payment_hook_payload {
|
|
|
|
struct lightningd *ld;
|
|
|
|
/* Set to NULL if it is deleted while waiting for plugin */
|
2019-12-12 00:55:45 +01:00
|
|
|
struct htlc_set *set;
|
2019-04-11 02:10:27 +02:00
|
|
|
/* What invoice it's trying to pay. */
|
2019-06-12 02:38:54 +02:00
|
|
|
const struct json_escape *label;
|
2019-04-11 02:10:27 +02:00
|
|
|
/* Amount it's offering. */
|
|
|
|
struct amount_msat msat;
|
|
|
|
/* Preimage we'll give it if succeeds. */
|
|
|
|
struct preimage preimage;
|
|
|
|
/* FIXME: Include raw payload! */
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
invoice_payment_serialize(struct invoice_payment_hook_payload *payload,
|
|
|
|
struct json_stream *stream)
|
|
|
|
{
|
|
|
|
json_object_start(stream, "payment");
|
|
|
|
json_add_escaped_string(stream, "label", payload->label);
|
2019-11-26 02:33:19 +01:00
|
|
|
json_add_preimage(stream, "preimage", &payload->preimage);
|
2019-04-11 02:10:27 +02:00
|
|
|
json_add_string(stream, "msat",
|
|
|
|
type_to_string(tmpctx, struct amount_msat,
|
|
|
|
&payload->msat));
|
|
|
|
json_object_end(stream); /* .payment */
|
|
|
|
}
|
|
|
|
|
2019-12-12 00:55:45 +01:00
|
|
|
/* Set times out or HTLC deleted? Remove set ptr from payload so we
|
|
|
|
* know to ignore plugin return */
|
|
|
|
static void invoice_payload_remove_set(struct htlc_set *set,
|
2019-04-16 02:10:59 +02:00
|
|
|
struct invoice_payment_hook_payload *payload)
|
|
|
|
{
|
2019-12-12 00:55:45 +01:00
|
|
|
assert(payload->set == set);
|
|
|
|
payload->set = NULL;
|
2019-04-16 02:10:59 +02:00
|
|
|
}
|
|
|
|
|
2020-02-21 06:08:39 +01:00
|
|
|
static const u8 *hook_gives_failmsg(const tal_t *ctx,
|
2020-04-15 12:19:46 +02:00
|
|
|
struct lightningd *ld,
|
2020-02-21 06:08:39 +01:00
|
|
|
const struct htlc_in *hin,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *toks)
|
2019-04-11 02:10:27 +02:00
|
|
|
{
|
2020-01-31 06:40:26 +01:00
|
|
|
const jsmntok_t *resulttok;
|
2019-04-16 02:16:22 +02:00
|
|
|
const jsmntok_t *t;
|
2019-04-11 02:10:27 +02:00
|
|
|
unsigned int val;
|
|
|
|
|
2019-04-16 02:10:59 +02:00
|
|
|
/* No plugin registered on hook at all? */
|
|
|
|
if (!buffer)
|
2020-02-21 06:08:39 +01:00
|
|
|
return NULL;
|
2019-04-16 02:10:59 +02:00
|
|
|
|
2020-01-31 06:40:26 +01:00
|
|
|
resulttok = json_get_member(buffer, toks, "result");
|
|
|
|
if (resulttok) {
|
|
|
|
if (json_tok_streq(buffer, resulttok, "continue")) {
|
2020-02-21 06:08:39 +01:00
|
|
|
return NULL;
|
2020-01-31 06:40:26 +01:00
|
|
|
} else if (json_tok_streq(buffer, resulttok, "reject")) {
|
2020-04-15 12:19:46 +02:00
|
|
|
return failmsg_incorrect_or_unknown(ctx, ld, hin);
|
2020-01-31 06:40:26 +01:00
|
|
|
} else
|
|
|
|
fatal("Invalid invoice_payment hook result: %.*s",
|
|
|
|
toks[0].end - toks[0].start, buffer);
|
|
|
|
}
|
|
|
|
|
2020-02-21 06:10:45 +01:00
|
|
|
t = json_get_member(buffer, toks, "failure_message");
|
|
|
|
if (t) {
|
|
|
|
const u8 *failmsg = json_tok_bin_from_hex(ctx, buffer, t);
|
|
|
|
if (!failmsg)
|
|
|
|
fatal("Invalid invoice_payment_hook failure_message: %.*s",
|
|
|
|
toks[0].end - toks[1].start, buffer);
|
|
|
|
return failmsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!deprecated_apis)
|
|
|
|
return NULL;
|
|
|
|
|
2019-04-16 02:16:22 +02:00
|
|
|
t = json_get_member(buffer, toks, "failure_code");
|
2020-02-21 06:10:45 +01:00
|
|
|
if (!t) {
|
2020-01-31 06:40:26 +01:00
|
|
|
static bool warned = false;
|
|
|
|
if (!warned) {
|
|
|
|
warned = true;
|
2020-04-15 12:19:46 +02:00
|
|
|
log_unusual(ld->log,
|
2020-01-31 06:40:26 +01:00
|
|
|
"Plugin did not return object with "
|
2020-02-21 06:10:45 +01:00
|
|
|
"'result' or 'failure_message' fields. "
|
2020-01-31 06:40:26 +01:00
|
|
|
"This is now deprecated and you should "
|
|
|
|
"return {'result': 'continue' } or "
|
|
|
|
"{'result': 'reject'} or "
|
2020-02-21 06:10:45 +01:00
|
|
|
"{'failure_message'... instead.");
|
2020-01-31 06:40:26 +01:00
|
|
|
}
|
2020-04-15 12:19:46 +02:00
|
|
|
return failmsg_incorrect_or_unknown(ctx, ld, hin);
|
2020-01-31 06:40:26 +01:00
|
|
|
}
|
2019-04-16 02:10:59 +02:00
|
|
|
|
2019-04-11 02:10:27 +02:00
|
|
|
if (!json_to_number(buffer, t, &val))
|
|
|
|
fatal("Invalid invoice_payment_hook failure_code: %.*s",
|
|
|
|
toks[0].end - toks[1].start, buffer);
|
|
|
|
|
2020-02-21 06:08:39 +01:00
|
|
|
if (val == WIRE_TEMPORARY_NODE_FAILURE)
|
|
|
|
return towire_temporary_node_failure(ctx);
|
|
|
|
if (val != WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS)
|
|
|
|
log_broken(hin->key.channel->log,
|
|
|
|
"invoice_payment hook returned failcode %u,"
|
|
|
|
" changing to incorrect_or_unknown_payment_details",
|
|
|
|
val);
|
|
|
|
|
2020-04-15 12:19:46 +02:00
|
|
|
return failmsg_incorrect_or_unknown(ctx, ld, hin);
|
2019-04-11 02:10:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-04-15 12:20:41 +02:00
|
|
|
invoice_payment_hook_cb(struct invoice_payment_hook_payload *payload STEALS,
|
2019-04-16 02:10:59 +02:00
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *toks)
|
2019-04-11 02:10:27 +02:00
|
|
|
{
|
|
|
|
struct lightningd *ld = payload->ld;
|
|
|
|
struct invoice invoice;
|
2020-02-21 06:08:39 +01:00
|
|
|
const u8 *failmsg;
|
2019-04-11 02:10:27 +02:00
|
|
|
|
2019-07-21 13:39:15 +02:00
|
|
|
/* We notify here to benefit from the payload and because the hook callback is
|
|
|
|
* called even if the hook is not registered. */
|
|
|
|
notify_invoice_payment(ld, payload->msat, payload->preimage, payload->label);
|
|
|
|
|
2019-12-12 00:55:45 +01:00
|
|
|
tal_del_destructor2(payload->set, invoice_payload_remove_set, payload);
|
2019-04-11 02:10:27 +02:00
|
|
|
/* We want to free this, whatever happens. */
|
|
|
|
tal_steal(tmpctx, payload);
|
|
|
|
|
|
|
|
/* If peer dies or something, this can happen. */
|
2019-12-12 00:55:45 +01:00
|
|
|
if (!payload->set) {
|
2019-04-11 02:10:27 +02:00
|
|
|
log_debug(ld->log, "invoice '%s' paying htlc_in has gone!",
|
|
|
|
payload->label->s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If invoice gets paid meanwhile (plugin responds out-of-order?) then
|
|
|
|
* we can also fail */
|
|
|
|
if (!wallet_invoice_find_by_label(ld->wallet, &invoice, payload->label)) {
|
2020-02-21 06:08:39 +01:00
|
|
|
htlc_set_fail(payload->set, take(failmsg_incorrect_or_unknown(
|
2020-04-15 12:19:46 +02:00
|
|
|
NULL, ld, payload->set->htlcs[0])));
|
2019-04-11 02:10:27 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-16 02:10:59 +02:00
|
|
|
/* Did we have a hook result? */
|
2020-04-15 12:19:46 +02:00
|
|
|
failmsg = hook_gives_failmsg(NULL, ld,
|
2020-02-21 06:08:39 +01:00
|
|
|
payload->set->htlcs[0], buffer, toks);
|
|
|
|
if (failmsg) {
|
|
|
|
htlc_set_fail(payload->set, take(failmsg));
|
2019-04-11 02:10:27 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-12 00:55:45 +01:00
|
|
|
log_info(ld->log, "Resolved invoice '%s' with amount %s in %zu htlcs",
|
|
|
|
payload->label->s,
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &payload->msat),
|
|
|
|
tal_count(payload->set->htlcs));
|
2019-04-11 02:10:27 +02:00
|
|
|
wallet_invoice_resolve(ld->wallet, invoice, payload->msat);
|
2019-12-12 00:55:45 +01:00
|
|
|
htlc_set_fulfill(payload->set, &payload->preimage);
|
2019-04-11 02:10:27 +02:00
|
|
|
}
|
|
|
|
|
2020-04-15 12:21:34 +02:00
|
|
|
REGISTER_SINGLE_PLUGIN_HOOK(invoice_payment,
|
|
|
|
invoice_payment_hook_cb,
|
|
|
|
invoice_payment_serialize,
|
|
|
|
struct invoice_payment_hook_payload *);
|
2019-04-11 02:10:27 +02:00
|
|
|
|
2019-12-12 00:55:45 +01:00
|
|
|
const struct invoice_details *
|
|
|
|
invoice_check_payment(const tal_t *ctx,
|
|
|
|
struct lightningd *ld,
|
|
|
|
const struct sha256 *payment_hash,
|
|
|
|
const struct amount_msat msat,
|
|
|
|
const struct secret *payment_secret)
|
2019-04-11 02:08:55 +02:00
|
|
|
{
|
|
|
|
struct invoice invoice;
|
|
|
|
const struct invoice_details *details;
|
|
|
|
|
2019-12-12 00:55:45 +01:00
|
|
|
/* BOLT #4:
|
|
|
|
* - if the payment hash has already been paid:
|
|
|
|
* - MAY treat the payment hash as unknown.
|
|
|
|
* - MAY succeed in accepting the HTLC.
|
|
|
|
*...
|
|
|
|
* - if the payment hash is unknown:
|
|
|
|
* - MUST fail the HTLC.
|
|
|
|
* - MUST return an `incorrect_or_unknown_payment_details` error.
|
|
|
|
*/
|
2020-07-20 07:49:52 +02:00
|
|
|
if (!wallet_invoice_find_unpaid(ld->wallet, &invoice, payment_hash)) {
|
|
|
|
log_debug(ld->log, "Unknown paid invoice %s",
|
|
|
|
type_to_string(tmpctx, struct sha256, payment_hash));
|
|
|
|
if (wallet_invoice_find_by_rhash(ld->wallet, &invoice, payment_hash)) {
|
|
|
|
log_debug(ld->log, "ALREADY paid invoice %s",
|
|
|
|
type_to_string(tmpctx, struct sha256, payment_hash));
|
|
|
|
}
|
2019-12-12 00:55:45 +01:00
|
|
|
return NULL;
|
2020-07-20 07:49:52 +02:00
|
|
|
}
|
2019-04-11 02:08:55 +02:00
|
|
|
|
2019-12-12 00:55:45 +01:00
|
|
|
details = wallet_invoice_details(ctx, ld->wallet, invoice);
|
2019-11-23 01:19:23 +01:00
|
|
|
|
2020-01-31 02:40:36 +01:00
|
|
|
/* BOLT #4:
|
2019-12-12 00:55:45 +01:00
|
|
|
* - if the `payment_secret` doesn't match the expected value for that
|
|
|
|
* `payment_hash`, or the `payment_secret` is required and is not
|
|
|
|
* present:
|
|
|
|
* - MUST fail the HTLC.
|
2019-11-23 01:19:23 +01:00
|
|
|
*/
|
|
|
|
if (feature_is_set(details->features, COMPULSORY_FEATURE(OPT_VAR_ONION))
|
2020-04-07 09:10:30 +02:00
|
|
|
&& !payment_secret) {
|
|
|
|
log_debug(ld->log, "Attept to pay %s without secret",
|
|
|
|
type_to_string(tmpctx, struct sha256, &details->rhash));
|
2019-12-12 00:55:45 +01:00
|
|
|
return tal_free(details);
|
2020-04-07 09:10:30 +02:00
|
|
|
}
|
2019-11-23 01:19:23 +01:00
|
|
|
|
|
|
|
if (payment_secret) {
|
|
|
|
struct secret expected;
|
|
|
|
|
|
|
|
invoice_secret(&details->r, &expected);
|
2020-04-07 09:10:30 +02:00
|
|
|
if (!secret_eq_consttime(payment_secret, &expected)) {
|
|
|
|
log_debug(ld->log, "Attept to pay %s with wrong secret",
|
|
|
|
type_to_string(tmpctx, struct sha256,
|
|
|
|
&details->rhash));
|
2019-12-12 00:55:45 +01:00
|
|
|
return tal_free(details);
|
2020-04-07 09:10:30 +02:00
|
|
|
}
|
2019-11-23 01:19:23 +01:00
|
|
|
}
|
|
|
|
|
2019-04-11 02:08:55 +02:00
|
|
|
/* BOLT #4:
|
|
|
|
*
|
|
|
|
* An _intermediate hop_ MUST NOT, but the _final node_:
|
|
|
|
*...
|
|
|
|
* - if the amount paid is less than the amount expected:
|
|
|
|
* - MUST fail the HTLC.
|
|
|
|
*/
|
|
|
|
if (details->msat != NULL) {
|
|
|
|
struct amount_msat twice;
|
|
|
|
|
2020-07-20 07:49:52 +02:00
|
|
|
if (amount_msat_less(msat, *details->msat)) {
|
|
|
|
log_debug(ld->log, "Attept to pay %s with amount %s < %s",
|
|
|
|
type_to_string(tmpctx, struct sha256,
|
|
|
|
&details->rhash),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &msat),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, details->msat));
|
2019-12-12 00:55:45 +01:00
|
|
|
return tal_free(details);
|
2020-07-20 07:49:52 +02:00
|
|
|
}
|
2019-04-11 02:08:55 +02:00
|
|
|
|
|
|
|
if (amount_msat_add(&twice, *details->msat, *details->msat)
|
|
|
|
&& amount_msat_greater(msat, twice)) {
|
2020-07-20 07:49:52 +02:00
|
|
|
log_debug(ld->log, "Attept to pay %s with amount %s > %s",
|
|
|
|
type_to_string(tmpctx, struct sha256,
|
|
|
|
&details->rhash),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, details->msat),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &twice));
|
2019-04-11 02:08:55 +02:00
|
|
|
/* BOLT #4:
|
|
|
|
*
|
2019-12-12 00:55:45 +01:00
|
|
|
* - if the amount paid is more than twice the amount
|
|
|
|
* expected:
|
|
|
|
* - SHOULD fail the HTLC.
|
2019-04-11 02:08:55 +02:00
|
|
|
*/
|
2019-12-12 00:55:45 +01:00
|
|
|
return tal_free(details);
|
2019-04-11 02:08:55 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-12 00:55:45 +01:00
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
|
|
|
void invoice_try_pay(struct lightningd *ld,
|
2019-12-12 00:55:45 +01:00
|
|
|
struct htlc_set *set,
|
|
|
|
const struct invoice_details *details)
|
2019-12-12 00:55:45 +01:00
|
|
|
{
|
|
|
|
struct invoice_payment_hook_payload *payload;
|
|
|
|
|
2020-04-15 12:20:41 +02:00
|
|
|
payload = tal(NULL, struct invoice_payment_hook_payload);
|
2019-04-11 02:10:27 +02:00
|
|
|
payload->ld = ld;
|
|
|
|
payload->label = tal_steal(payload, details->label);
|
2019-12-12 00:55:45 +01:00
|
|
|
payload->msat = set->so_far;
|
2019-04-11 02:10:27 +02:00
|
|
|
payload->preimage = details->r;
|
2019-12-12 00:55:45 +01:00
|
|
|
payload->set = set;
|
|
|
|
tal_add_destructor2(set, invoice_payload_remove_set, payload);
|
2019-04-11 02:10:27 +02:00
|
|
|
|
2020-04-15 12:20:41 +02:00
|
|
|
plugin_hook_call_invoice_payment(ld, payload);
|
2019-04-11 02:08:55 +02:00
|
|
|
}
|
|
|
|
|
2017-11-22 01:25:39 +01:00
|
|
|
static bool hsm_sign_b11(const u5 *u5bytes,
|
|
|
|
const u8 *hrpu8,
|
|
|
|
secp256k1_ecdsa_recoverable_signature *rsig,
|
|
|
|
struct lightningd *ld)
|
|
|
|
{
|
2020-08-25 03:55:38 +02:00
|
|
|
u8 *msg = towire_hsmd_sign_invoice(NULL, u5bytes, hrpu8);
|
2017-11-22 01:25:39 +01:00
|
|
|
|
|
|
|
if (!wire_sync_write(ld->hsm_fd, take(msg)))
|
|
|
|
fatal("Could not write to HSM: %s", strerror(errno));
|
|
|
|
|
2018-07-09 13:17:59 +02:00
|
|
|
msg = wire_sync_read(tmpctx, ld->hsm_fd);
|
2020-08-25 03:55:38 +02:00
|
|
|
if (!fromwire_hsmd_sign_invoice_reply(msg, rsig))
|
2017-11-22 01:25:39 +01:00
|
|
|
fatal("HSM gave bad sign_invoice_reply %s",
|
|
|
|
tal_hex(msg, msg));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *parse_fallback(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *fallback,
|
|
|
|
const u8 **fallback_script)
|
2018-04-05 07:13:51 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
enum address_parse_result fallback_parse;
|
|
|
|
|
|
|
|
fallback_parse
|
2019-10-06 14:12:41 +02:00
|
|
|
= json_to_address_scriptpubkey(cmd,
|
2019-10-15 12:58:30 +02:00
|
|
|
chainparams,
|
2019-10-06 14:12:41 +02:00
|
|
|
buffer, fallback,
|
|
|
|
fallback_script);
|
2018-04-05 07:13:51 +02:00
|
|
|
if (fallback_parse == ADDRESS_PARSE_UNRECOGNIZED) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, LIGHTNINGD,
|
|
|
|
"Fallback address not valid");
|
2018-04-05 07:13:51 +02:00
|
|
|
} else if (fallback_parse == ADDRESS_PARSE_WRONG_NETWORK) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, LIGHTNINGD,
|
|
|
|
"Fallback address does not match our network %s",
|
2019-10-15 12:58:30 +02:00
|
|
|
chainparams->network_name);
|
2018-04-05 07:13:51 +02:00
|
|
|
}
|
2018-12-16 05:52:06 +01:00
|
|
|
return NULL;
|
2018-04-05 07:13:51 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
/** incoming_capacity
|
|
|
|
*
|
|
|
|
* @brief Determine the ability of the peer to pay us.
|
|
|
|
*
|
|
|
|
* @param ld - the lightningd.
|
|
|
|
* @param c - the channel to check.
|
|
|
|
* @param capacity_to_pay_us - out; if this returns true,
|
|
|
|
* the pointed-to `struct amount_msat` will contain how
|
|
|
|
* much the peer can pay us at maximum.
|
|
|
|
*
|
|
|
|
* @return false if the peer cannot pay to us, true if
|
|
|
|
* the peer can pay us and `capacity_to_pay_us` is set.
|
|
|
|
*/
|
|
|
|
static bool incoming_capacity(struct lightningd *ld,
|
|
|
|
struct channel *c,
|
|
|
|
struct amount_msat *capacity_to_pay_us)
|
|
|
|
{
|
|
|
|
struct amount_msat their_msat;
|
|
|
|
if (!amount_sat_sub_msat(&their_msat, c->funding, c->our_msat)) {
|
|
|
|
log_broken(ld->log,
|
|
|
|
"underflow: funding %s - our_msat %s",
|
|
|
|
type_to_string(tmpctx, struct amount_sat,
|
|
|
|
&c->funding),
|
|
|
|
type_to_string(tmpctx, struct amount_msat,
|
|
|
|
&c->our_msat));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!amount_msat_sub_sat(capacity_to_pay_us, their_msat,
|
|
|
|
c->our_config.channel_reserve))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-09 17:35:28 +02:00
|
|
|
/*
|
|
|
|
* From array of incoming channels [inchan], find suitable ones for
|
|
|
|
* a payment-to-us of [amount_needed], using criteria:
|
|
|
|
* 1. Channel's peer is known, in state CHANNELD_NORMAL and is online.
|
|
|
|
* 2. Channel's peer capacity to pay us is sufficient.
|
|
|
|
*
|
|
|
|
* Then use weighted reservoir sampling, which makes probing channel balances
|
|
|
|
* harder, to choose one channel from the set of suitable channels. It favors
|
|
|
|
* channels that have less balance on our side as fraction of their capacity.
|
|
|
|
*
|
|
|
|
* [any_offline] is set if the peer of any suitable channel appears offline.
|
|
|
|
*/
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
static struct route_info **select_inchan(const tal_t *ctx,
|
|
|
|
struct lightningd *ld,
|
2019-04-09 17:35:28 +02:00
|
|
|
struct amount_msat amount_needed,
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
const struct route_info *inchans,
|
2019-12-17 07:11:08 +01:00
|
|
|
const bool *deadends,
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
bool *any_offline)
|
|
|
|
{
|
2019-04-09 17:35:28 +02:00
|
|
|
/* BOLT11 struct wants an array of arrays (can provide multiple routes) */
|
|
|
|
struct route_info **R;
|
|
|
|
double wsum, p;
|
|
|
|
|
|
|
|
struct sample {
|
|
|
|
const struct route_info *route;
|
|
|
|
double weight;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sample *S = tal_arr(tmpctx, struct sample, 0);
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
|
|
|
|
*any_offline = false;
|
|
|
|
|
2019-04-09 17:35:28 +02:00
|
|
|
/* Collect suitable channels and assign each a weight. */
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
for (size_t i = 0; i < tal_count(inchans); i++) {
|
|
|
|
struct peer *peer;
|
|
|
|
struct channel *c;
|
2019-04-09 17:35:28 +02:00
|
|
|
struct sample sample;
|
2020-08-05 15:50:38 +02:00
|
|
|
struct amount_msat capacity_to_pay_us, excess, capacity;
|
2019-04-09 17:35:28 +02:00
|
|
|
struct amount_sat cumulative_reserve;
|
|
|
|
double excess_frac;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
|
|
|
|
/* Do we know about this peer? */
|
|
|
|
peer = peer_by_id(ld, &inchans[i].pubkey);
|
|
|
|
if (!peer)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Does it have a channel in state CHANNELD_NORMAL */
|
|
|
|
c = peer_normal_channel(peer);
|
|
|
|
if (!c)
|
|
|
|
continue;
|
|
|
|
|
2019-12-17 07:11:08 +01:00
|
|
|
/* Is it a dead-end? */
|
|
|
|
if (deadends[i])
|
|
|
|
continue;
|
|
|
|
|
2019-04-09 17:35:28 +02:00
|
|
|
/* Channel balance as seen by our node:
|
|
|
|
|
|
|
|
|<----------------- capacity ----------------->|
|
|
|
|
. .
|
|
|
|
. |<------------------ their_msat -------------------->|
|
|
|
|
. | . |
|
|
|
|
. |<----- capacity_to_pay_us ----->|<- their_reserve ->|
|
|
|
|
. | | |
|
|
|
|
. |<- amount_needed --><- excess ->| |
|
|
|
|
. | | |
|
|
|
|
|-------|-------------|--------------------------------|-------------------|
|
|
|
|
0 ^ ^ ^ funding
|
|
|
|
our_reserve our_msat */
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
/* Can the peer pay to us, and if so how much? */
|
|
|
|
if (!incoming_capacity(ld, c, &capacity_to_pay_us))
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
continue;
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
/* Does the peer have sufficient balance to pay us,
|
|
|
|
* even after having taken into account their reserve? */
|
2019-04-09 17:35:28 +02:00
|
|
|
if (!amount_msat_sub(&excess, capacity_to_pay_us, amount_needed))
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Is it offline? */
|
|
|
|
if (c->owner == NULL) {
|
|
|
|
*any_offline = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-04-09 17:35:28 +02:00
|
|
|
/* Find capacity and calculate its excess fraction */
|
|
|
|
if (!amount_sat_add(&cumulative_reserve,
|
|
|
|
c->our_config.channel_reserve,
|
|
|
|
c->channel_info.their_config.channel_reserve)
|
|
|
|
|| !amount_sat_to_msat(&capacity, c->funding)
|
|
|
|
|| !amount_msat_sub_sat(&capacity, capacity, cumulative_reserve)) {
|
|
|
|
log_broken(ld->log, "Channel %s capacity overflow!",
|
|
|
|
type_to_string(tmpctx, struct short_channel_id, c->scid));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-08-05 05:56:32 +02:00
|
|
|
excess_frac = amount_msat_ratio(excess, capacity);
|
2019-04-09 17:35:28 +02:00
|
|
|
|
|
|
|
sample.route = &inchans[i];
|
|
|
|
sample.weight = excess_frac;
|
|
|
|
tal_arr_expand(&S, sample);
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
}
|
|
|
|
|
2019-04-09 17:35:28 +02:00
|
|
|
if (!tal_count(S))
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
return NULL;
|
|
|
|
|
2019-04-09 17:35:28 +02:00
|
|
|
/* Use weighted reservoir sampling, see:
|
|
|
|
* https://en.wikipedia.org/wiki/Reservoir_sampling#Algorithm_A-Chao
|
|
|
|
* But (currently) the result will consist of only one sample (k=1) */
|
|
|
|
R = tal_arr(ctx, struct route_info *, 1);
|
|
|
|
R[0] = tal_dup(R, struct route_info, S[0].route);
|
|
|
|
wsum = S[0].weight;
|
|
|
|
|
|
|
|
for (size_t i = 1; i < tal_count(S); i++) {
|
|
|
|
wsum += S[i].weight;
|
|
|
|
p = S[i].weight / wsum;
|
|
|
|
double random_1 = pseudorand_double(); /* range [0,1) */
|
|
|
|
|
|
|
|
if (random_1 <= p)
|
|
|
|
R[0] = tal_dup(R, struct route_info, S[i].route);
|
|
|
|
}
|
|
|
|
|
|
|
|
return R;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
/** select_inchan_mpp
|
|
|
|
*
|
|
|
|
* @brief fallback in case select_inchan cannot find a *single*
|
|
|
|
* channel capable of accepting the payment as a whole.
|
|
|
|
* Also the main routehint-selector if we are completely unpublished
|
|
|
|
* (i.e. all our channels are unpublished), since if we are completely
|
|
|
|
* unpublished then the payer cannot fall back to just directly routing
|
|
|
|
* to us.
|
|
|
|
*/
|
|
|
|
static struct route_info **select_inchan_mpp(const tal_t *ctx,
|
|
|
|
struct lightningd *ld,
|
|
|
|
struct amount_msat amount_needed,
|
|
|
|
const struct route_info *inchans,
|
|
|
|
const bool *deadends,
|
|
|
|
bool *any_offline,
|
|
|
|
bool *warning_mpp_capacity)
|
|
|
|
{
|
|
|
|
/* The total amount we have gathered for incoming channels. */
|
|
|
|
struct amount_msat gathered;
|
|
|
|
/* Channels we have already processed. */
|
|
|
|
struct list_head processed;
|
|
|
|
/* Routehint array. */
|
|
|
|
struct route_info **routehints;
|
|
|
|
|
|
|
|
gathered = AMOUNT_MSAT(0);
|
|
|
|
list_head_init(&processed);
|
|
|
|
routehints = tal_arr(ctx, struct route_info *, 0);
|
|
|
|
|
|
|
|
while (amount_msat_less(gathered, amount_needed)
|
|
|
|
&& !list_empty(&ld->rr_channels)) {
|
|
|
|
struct channel *c;
|
|
|
|
struct amount_msat capacity_to_pay_us;
|
|
|
|
size_t found_i;
|
|
|
|
const struct route_info *found;
|
|
|
|
|
|
|
|
/* Get a channel and put it in the processed list. */
|
|
|
|
c = list_pop(&ld->rr_channels, struct channel, rr_list);
|
|
|
|
list_add_tail(&processed, &c->rr_list);
|
|
|
|
|
|
|
|
/* Is the channel even useful? */
|
|
|
|
if (c->state != CHANNELD_NORMAL)
|
|
|
|
continue;
|
|
|
|
/* SCID should have been set when we locked in, and we
|
|
|
|
* can only CHANNELD_NORMAL if both us and peer are
|
|
|
|
* locked in. */
|
|
|
|
assert(c->scid != NULL);
|
|
|
|
|
|
|
|
/* Is the peer offline? */
|
|
|
|
if (c->owner == NULL) {
|
|
|
|
*any_offline = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Can the peer pay to us? */
|
|
|
|
if (!incoming_capacity(ld, c, &capacity_to_pay_us))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Is the channel in the inchans input? */
|
|
|
|
found = NULL;
|
|
|
|
found_i = 0;
|
|
|
|
for (size_t i = 0; i < tal_count(inchans); ++i) {
|
|
|
|
if (short_channel_id_eq(&inchans[i].short_channel_id,
|
|
|
|
c->scid)) {
|
|
|
|
found = &inchans[i];
|
|
|
|
found_i = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Is it a deadend? */
|
|
|
|
if (deadends[found_i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Add to current routehints set. */
|
|
|
|
if (!amount_msat_add(&gathered, gathered, capacity_to_pay_us)) {
|
|
|
|
log_broken(ld->log,
|
|
|
|
"Gathered channel capacity overflow: "
|
|
|
|
"%s + %s",
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &gathered),
|
|
|
|
type_to_string(tmpctx, struct amount_msat, &capacity_to_pay_us));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tal_arr_expand(&routehints,
|
|
|
|
tal_dup(routehints, struct route_info, found));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Append the processed list back to the rr_channels. */
|
|
|
|
list_append_list(&ld->rr_channels, &processed);
|
|
|
|
/* Check if we gathered enough. */
|
|
|
|
*warning_mpp_capacity = amount_msat_less(gathered, amount_needed);
|
|
|
|
|
|
|
|
return routehints;
|
|
|
|
}
|
|
|
|
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
/* Encapsulating struct while we wait for gossipd to give us incoming channels */
|
2019-12-17 07:11:08 +01:00
|
|
|
struct chanhints {
|
|
|
|
bool expose_all_private;
|
|
|
|
struct short_channel_id *hints;
|
|
|
|
};
|
|
|
|
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
struct invoice_info {
|
|
|
|
struct command *cmd;
|
|
|
|
struct preimage payment_preimage;
|
|
|
|
struct bolt11 *b11;
|
2019-06-12 02:38:54 +02:00
|
|
|
struct json_escape *label;
|
2019-12-17 07:11:08 +01:00
|
|
|
struct chanhints *chanhints;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
};
|
|
|
|
|
2019-12-17 07:11:08 +01:00
|
|
|
static void append_routes(struct route_info **dst, const struct route_info *src)
|
|
|
|
{
|
|
|
|
size_t n = tal_count(*dst);
|
|
|
|
|
|
|
|
tal_resize(dst, n + tal_count(src));
|
|
|
|
memcpy(*dst + n, src, tal_count(src) * sizeof(*src));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void append_bools(bool **dst, const bool *src)
|
|
|
|
{
|
|
|
|
size_t n = tal_count(*dst);
|
|
|
|
|
|
|
|
tal_resize(dst, n + tal_count(src));
|
|
|
|
memcpy(*dst + n, src, tal_count(src) * sizeof(*src));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool all_true(const bool *barr, size_t n)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < n; i++) {
|
|
|
|
if (!barr[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-17 07:18:13 +01:00
|
|
|
static bool scid_in_arr(const struct short_channel_id *scidarr,
|
|
|
|
const struct short_channel_id *scid)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < tal_count(scidarr); i++)
|
|
|
|
if (short_channel_id_eq(&scidarr[i], scid))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
static void gossipd_incoming_channels_reply(struct subd *gossipd,
|
|
|
|
const u8 *msg,
|
|
|
|
const int *fs,
|
|
|
|
struct invoice_info *info)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2018-10-19 03:17:49 +02:00
|
|
|
struct json_stream *response;
|
2019-12-17 07:11:08 +01:00
|
|
|
struct route_info *inchans, *private;
|
|
|
|
bool *inchan_deadends, *private_deadends;
|
2018-02-23 02:04:47 +01:00
|
|
|
struct invoice invoice;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
char *b11enc;
|
2018-07-27 12:57:02 +02:00
|
|
|
const struct invoice_details *details;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
struct wallet *wallet = info->cmd->ld->wallet;
|
2019-12-17 07:11:08 +01:00
|
|
|
const struct chanhints *chanhints = info->chanhints;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
bool any_offline = false;
|
|
|
|
bool warning_mpp = false;
|
|
|
|
bool warning_mpp_capacity = false;
|
|
|
|
bool node_unpublished;
|
|
|
|
|
2020-08-25 04:05:45 +02:00
|
|
|
if (!fromwire_gossipd_get_incoming_channels_reply(tmpctx, msg,
|
2020-08-05 15:50:38 +02:00
|
|
|
&inchans,
|
|
|
|
&inchan_deadends,
|
|
|
|
&private,
|
|
|
|
&private_deadends))
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
fatal("Gossip gave bad GOSSIP_GET_INCOMING_CHANNELS_REPLY %s",
|
|
|
|
tal_hex(msg, msg));
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
node_unpublished = (tal_count(inchans) == 0)
|
|
|
|
&& (tal_count(private) > 0);
|
|
|
|
|
2019-12-17 07:11:08 +01:00
|
|
|
/* fromwire explicitly makes empty arrays into NULL */
|
|
|
|
if (!inchans) {
|
|
|
|
inchans = tal_arr(tmpctx, struct route_info, 0);
|
|
|
|
inchan_deadends = tal_arr(tmpctx, bool, 0);
|
|
|
|
}
|
|
|
|
|
2019-12-17 07:18:13 +01:00
|
|
|
if (chanhints && chanhints->expose_all_private) {
|
2019-12-17 07:11:08 +01:00
|
|
|
append_routes(&inchans, private);
|
|
|
|
append_bools(&inchan_deadends, private_deadends);
|
2019-12-17 07:18:13 +01:00
|
|
|
} else if (chanhints && chanhints->hints) {
|
|
|
|
/* Start by considering all channels as candidates */
|
|
|
|
append_routes(&inchans, private);
|
|
|
|
append_bools(&inchan_deadends, private_deadends);
|
|
|
|
|
|
|
|
/* Consider only hints they gave */
|
|
|
|
for (size_t i = 0; i < tal_count(inchans); i++) {
|
|
|
|
if (!scid_in_arr(chanhints->hints,
|
|
|
|
&inchans[i].short_channel_id)) {
|
|
|
|
tal_arr_remove(&inchans, i);
|
|
|
|
tal_arr_remove(&inchan_deadends, i);
|
2020-04-08 09:40:58 +02:00
|
|
|
i--;
|
|
|
|
} else
|
|
|
|
/* If they specify directly, we don't
|
|
|
|
* care if it's a deadend */
|
|
|
|
inchan_deadends[i] = false;
|
2019-12-17 07:18:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If they told us to use scids and we couldn't, fail. */
|
|
|
|
if (tal_count(inchans) == 0
|
|
|
|
&& tal_count(chanhints->hints) != 0) {
|
|
|
|
was_pending(command_fail(info->cmd,
|
|
|
|
INVOICE_HINTS_GAVE_NO_ROUTES,
|
|
|
|
"None of those hints were suitable local channels"));
|
|
|
|
return;
|
|
|
|
}
|
2019-12-17 07:11:08 +01:00
|
|
|
} else {
|
2019-12-17 07:18:13 +01:00
|
|
|
assert(!chanhints);
|
2019-12-17 07:11:08 +01:00
|
|
|
/* By default, only consider private channels if there are
|
|
|
|
* no public channels *at all* */
|
|
|
|
if (tal_count(inchans) == 0) {
|
|
|
|
append_routes(&inchans, private);
|
|
|
|
append_bools(&inchan_deadends, private_deadends);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
if (tal_count(info->b11->routes) == 0) {
|
|
|
|
struct amount_msat needed;
|
|
|
|
needed = info->b11->msat ? *info->b11->msat : AMOUNT_MSAT(1);
|
|
|
|
|
|
|
|
/* If we are not completely unpublished, try with reservoir
|
|
|
|
* sampling first.
|
|
|
|
*
|
|
|
|
* Why do we not do this if we are completely unpublished?
|
|
|
|
* Because it is possible that multiple invoices will, by
|
|
|
|
* chance, select the same channel as routehint.
|
|
|
|
* This single channel might not be able to accept all the
|
|
|
|
* incoming payments on all the invoices generated.
|
|
|
|
* If we were published, that is fine because the payer can
|
|
|
|
* fall back to just attempting to route directly.
|
|
|
|
* But if we were unpublished, the only way for the payer to
|
|
|
|
* reach us would be via the routehints we provide, so we
|
|
|
|
* should make an effort to avoid overlapping incoming
|
|
|
|
* channels, which is done by select_inchan_mpp.
|
|
|
|
*/
|
|
|
|
if (!node_unpublished)
|
|
|
|
info->b11->routes = select_inchan(info->b11,
|
|
|
|
info->cmd->ld,
|
|
|
|
needed,
|
|
|
|
inchans,
|
|
|
|
inchan_deadends,
|
|
|
|
&any_offline);
|
|
|
|
/* If we are completely unpublished, or if the above reservoir
|
|
|
|
* sampling fails, select channels by round-robin. */
|
|
|
|
if (tal_count(info->b11->routes) == 0) {
|
|
|
|
info->b11->routes = select_inchan_mpp(info->b11,
|
|
|
|
info->cmd->ld,
|
|
|
|
needed,
|
|
|
|
inchans,
|
|
|
|
inchan_deadends,
|
|
|
|
&any_offline,
|
|
|
|
&warning_mpp_capacity);
|
|
|
|
warning_mpp = (tal_count(info->b11->routes) > 1);
|
|
|
|
}
|
|
|
|
}
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
|
|
|
|
/* FIXME: add private routes if necessary! */
|
|
|
|
b11enc = bolt11_encode(info, info->b11, false,
|
|
|
|
hsm_sign_b11, info->cmd->ld);
|
|
|
|
|
|
|
|
/* Check duplicate preimage (unlikely unless they specified it!) */
|
|
|
|
if (wallet_invoice_find_by_rhash(wallet,
|
|
|
|
&invoice, &info->b11->payment_hash)) {
|
2018-12-16 05:53:06 +01:00
|
|
|
was_pending(command_fail(info->cmd,
|
|
|
|
INVOICE_PREIMAGE_ALREADY_EXISTS,
|
|
|
|
"preimage already used"));
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wallet_invoice_create(wallet,
|
|
|
|
&invoice,
|
2019-02-21 03:38:35 +01:00
|
|
|
info->b11->msat,
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
info->label,
|
|
|
|
info->b11->expiry,
|
|
|
|
b11enc,
|
|
|
|
info->b11->description,
|
2019-11-23 01:19:23 +01:00
|
|
|
info->b11->features,
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
&info->payment_preimage,
|
|
|
|
&info->b11->payment_hash)) {
|
2018-12-16 05:53:06 +01:00
|
|
|
was_pending(command_fail(info->cmd, INVOICE_LABEL_ALREADY_EXISTS,
|
|
|
|
"Duplicate label '%s'",
|
|
|
|
info->label->s));
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get details */
|
|
|
|
details = wallet_invoice_details(info, wallet, invoice);
|
|
|
|
|
2018-10-19 03:17:48 +02:00
|
|
|
response = json_stream_success(info->cmd);
|
2019-08-10 10:39:04 +02:00
|
|
|
json_add_sha256(response, "payment_hash", &details->rhash);
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
json_add_u64(response, "expires_at", details->expiry_time);
|
|
|
|
json_add_string(response, "bolt11", details->bolt11);
|
|
|
|
|
2020-04-21 03:04:01 +02:00
|
|
|
notify_invoice_creation(info->cmd->ld, info->b11->msat,
|
|
|
|
info->payment_preimage, info->label);
|
|
|
|
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
/* Warn if there's not sufficient incoming capacity. */
|
|
|
|
if (tal_count(info->b11->routes) == 0) {
|
|
|
|
log_unusual(info->cmd->ld->log,
|
2019-02-21 04:45:56 +01:00
|
|
|
"invoice: insufficient incoming capacity for %s%s",
|
|
|
|
info->b11->msat
|
|
|
|
? type_to_string(tmpctx, struct amount_msat,
|
|
|
|
info->b11->msat)
|
|
|
|
: "0",
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
any_offline
|
|
|
|
? " (among currently connected peers)" : "");
|
|
|
|
|
2019-12-17 07:11:08 +01:00
|
|
|
if (tal_count(inchans) == 0)
|
|
|
|
json_add_string(response, "warning_capacity",
|
|
|
|
"No channels");
|
|
|
|
else if (all_true(inchan_deadends, tal_count(inchans)))
|
|
|
|
json_add_string(response, "warning_deadends",
|
|
|
|
"No channel with a peer that is not a dead end");
|
|
|
|
else if (any_offline)
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
json_add_string(response, "warning_offline",
|
2019-07-31 09:48:27 +02:00
|
|
|
"No channel with a peer that is currently connected"
|
|
|
|
" has sufficient incoming capacity");
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
else
|
|
|
|
json_add_string(response, "warning_capacity",
|
2019-12-17 07:11:08 +01:00
|
|
|
"No channel with a peer that has sufficient incoming capacity");
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 15:50:38 +02:00
|
|
|
if (warning_mpp)
|
|
|
|
json_add_string(response, "warning_mpp",
|
|
|
|
"The invoice might only be payable by MPP-capable payers.");
|
|
|
|
if (warning_mpp_capacity)
|
|
|
|
json_add_string(response, "warning_mpp_capacity",
|
|
|
|
"The total incoming capacity is still insufficient even if the payer had MPP capability.");
|
|
|
|
|
2018-12-16 05:53:06 +01:00
|
|
|
was_pending(command_success(info->cmd, response));
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
}
|
|
|
|
|
2019-01-15 05:00:27 +01:00
|
|
|
#if DEVELOPER
|
|
|
|
/* Since this is a dev-only option, we will crash if dev-routes is not
|
|
|
|
* an array-of-arrays-of-correct-items. */
|
|
|
|
static struct route_info *unpack_route(const tal_t *ctx,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *routetok)
|
|
|
|
{
|
2019-01-17 03:12:13 +01:00
|
|
|
const jsmntok_t *t;
|
|
|
|
size_t i;
|
|
|
|
struct route_info *route = tal_arr(ctx, struct route_info, routetok->size);
|
2019-01-15 05:00:27 +01:00
|
|
|
|
2019-01-17 03:12:13 +01:00
|
|
|
json_for_each_arr(i, t, routetok) {
|
2019-01-15 05:00:27 +01:00
|
|
|
const jsmntok_t *pubkey, *fee_base, *fee_prop, *scid, *cltv;
|
2019-01-17 03:12:13 +01:00
|
|
|
struct route_info *r = &route[i];
|
2019-01-15 05:00:27 +01:00
|
|
|
u32 cltv_u32;
|
|
|
|
|
|
|
|
pubkey = json_get_member(buffer, t, "id");
|
|
|
|
scid = json_get_member(buffer, t, "short_channel_id");
|
|
|
|
fee_base = json_get_member(buffer, t, "fee_base_msat");
|
|
|
|
fee_prop = json_get_member(buffer, t,
|
|
|
|
"fee_proportional_millionths");
|
|
|
|
cltv = json_get_member(buffer, t, "cltv_expiry_delta");
|
|
|
|
|
2019-04-08 11:58:32 +02:00
|
|
|
if (!json_to_node_id(buffer, pubkey, &r->pubkey)
|
2019-01-15 05:00:27 +01:00
|
|
|
|| !json_to_short_channel_id(buffer, scid,
|
2019-09-06 08:41:41 +02:00
|
|
|
&r->short_channel_id)
|
2019-01-17 03:12:13 +01:00
|
|
|
|| !json_to_number(buffer, fee_base, &r->fee_base_msat)
|
2019-01-15 05:00:27 +01:00
|
|
|
|| !json_to_number(buffer, fee_prop,
|
2019-01-17 03:12:13 +01:00
|
|
|
&r->fee_proportional_millionths)
|
2019-01-15 05:00:27 +01:00
|
|
|
|| !json_to_number(buffer, cltv, &cltv_u32))
|
|
|
|
abort();
|
|
|
|
/* We don't have a json_to_u16 */
|
2019-01-17 03:12:13 +01:00
|
|
|
r->cltv_expiry_delta = cltv_u32;
|
2019-01-15 05:00:27 +01:00
|
|
|
}
|
|
|
|
return route;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct route_info **unpack_routes(const tal_t *ctx,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *routestok)
|
|
|
|
{
|
|
|
|
struct route_info **routes;
|
2019-01-17 03:12:13 +01:00
|
|
|
const jsmntok_t *t;
|
|
|
|
size_t i;
|
2019-01-15 05:00:27 +01:00
|
|
|
|
|
|
|
if (!routestok)
|
|
|
|
return NULL;
|
|
|
|
|
2019-01-17 03:12:13 +01:00
|
|
|
routes = tal_arr(ctx, struct route_info *, routestok->size);
|
|
|
|
json_for_each_arr(i, t, routestok)
|
|
|
|
routes[i] = unpack_route(routes, buffer, t);
|
|
|
|
|
2019-01-15 05:00:27 +01:00
|
|
|
return routes;
|
|
|
|
}
|
|
|
|
#endif /* DEVELOPER */
|
|
|
|
|
2020-08-25 03:05:46 +02:00
|
|
|
static struct command_result *param_positive_msat_or_any(struct command *cmd,
|
|
|
|
const char *name,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *tok,
|
|
|
|
struct amount_msat **msat)
|
2019-02-21 01:45:57 +01:00
|
|
|
{
|
|
|
|
if (json_tok_streq(buffer, tok, "any")) {
|
|
|
|
*msat = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*msat = tal(cmd, struct amount_msat);
|
2020-08-25 03:05:46 +02:00
|
|
|
if (parse_amount_msat(*msat, buffer + tok->start, tok->end - tok->start)
|
|
|
|
&& !amount_msat_eq(**msat, AMOUNT_MSAT(0)))
|
2019-02-21 01:45:57 +01:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2020-08-25 03:05:46 +02:00
|
|
|
"'%s' should be positive millisatoshis or 'any',"
|
|
|
|
" not '%.*s'",
|
2019-02-21 01:45:57 +01:00
|
|
|
name,
|
|
|
|
tok->end - tok->start,
|
|
|
|
buffer + tok->start);
|
|
|
|
}
|
|
|
|
|
2019-04-10 06:58:24 +02:00
|
|
|
/* Parse time with optional suffix, return seconds */
|
|
|
|
static struct command_result *param_time(struct command *cmd, const char *name,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *tok,
|
|
|
|
uint64_t **secs)
|
|
|
|
{
|
|
|
|
/* We need to manipulate this, so make copy */
|
|
|
|
jsmntok_t timetok = *tok;
|
|
|
|
u64 mul;
|
|
|
|
char s;
|
|
|
|
struct {
|
|
|
|
char suffix;
|
|
|
|
u64 mul;
|
|
|
|
} suffixes[] = {
|
|
|
|
{ 's', 1 },
|
|
|
|
{ 'm', 60 },
|
|
|
|
{ 'h', 60*60 },
|
|
|
|
{ 'd', 24*60*60 },
|
|
|
|
{ 'w', 7*24*60*60 } };
|
|
|
|
|
|
|
|
mul = 1;
|
|
|
|
if (timetok.end == timetok.start)
|
|
|
|
s = '\0';
|
|
|
|
else
|
|
|
|
s = buffer[timetok.end - 1];
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(suffixes); i++) {
|
|
|
|
if (s == suffixes[i].suffix) {
|
|
|
|
mul = suffixes[i].mul;
|
|
|
|
timetok.end--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*secs = tal(cmd, uint64_t);
|
|
|
|
if (json_to_u64(buffer, &timetok, *secs)) {
|
|
|
|
if (mul_overflows_u64(**secs, mul)) {
|
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"'%s' string '%.*s' is too large",
|
|
|
|
name, tok->end - tok->start,
|
|
|
|
buffer + tok->start);
|
|
|
|
}
|
|
|
|
**secs *= mul;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"'%s' should be a number with optional {s,m,h,d,w} suffix, not '%.*s'",
|
|
|
|
name, tok->end - tok->start, buffer + tok->start);
|
|
|
|
}
|
|
|
|
|
2019-12-17 07:18:13 +01:00
|
|
|
static struct command_result *param_chanhints(struct command *cmd,
|
|
|
|
const char *name,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *tok,
|
|
|
|
struct chanhints **chanhints)
|
|
|
|
{
|
|
|
|
bool boolhint;
|
|
|
|
|
|
|
|
*chanhints = tal(cmd, struct chanhints);
|
|
|
|
|
|
|
|
/* Could be simply "true" or "false" */
|
|
|
|
if (json_to_bool(buffer, tok, &boolhint)) {
|
|
|
|
(*chanhints)->expose_all_private = boolhint;
|
|
|
|
(*chanhints)->hints
|
|
|
|
= tal_arr(*chanhints, struct short_channel_id, 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*chanhints)->expose_all_private = false;
|
|
|
|
/* Could be a single short_channel_id or an array */
|
|
|
|
if (tok->type == JSMN_ARRAY) {
|
|
|
|
size_t i;
|
|
|
|
const jsmntok_t *t;
|
|
|
|
|
|
|
|
(*chanhints)->hints
|
|
|
|
= tal_arr(*chanhints, struct short_channel_id,
|
|
|
|
tok->size);
|
|
|
|
json_for_each_arr(i, t, tok) {
|
|
|
|
if (!json_to_short_channel_id(buffer, t,
|
|
|
|
&(*chanhints)->hints[i])) {
|
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"'%s' should be a short channel id, not '%.*s'",
|
|
|
|
name, json_tok_full_len(t),
|
|
|
|
json_tok_full(buffer, t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise should be a short_channel_id */
|
|
|
|
return param_short_channel_id(cmd, name, buffer, tok,
|
|
|
|
&(*chanhints)->hints);
|
|
|
|
}
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_invoice(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
{
|
2018-08-29 22:44:04 +02:00
|
|
|
const jsmntok_t *fallbacks;
|
2018-07-16 22:48:38 +02:00
|
|
|
const jsmntok_t *preimagetok;
|
2019-02-21 01:45:57 +01:00
|
|
|
struct amount_msat *msatoshi_val;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
struct invoice_info *info;
|
2018-02-17 12:48:22 +01:00
|
|
|
const char *desc_val;
|
2018-04-05 07:13:51 +02:00
|
|
|
const u8 **fallback_scripts = NULL;
|
2018-08-13 18:16:41 +02:00
|
|
|
u64 *expiry;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
struct sha256 rhash;
|
2019-11-23 01:19:23 +01:00
|
|
|
struct secret payment_secret;
|
2019-01-15 05:00:27 +01:00
|
|
|
#if DEVELOPER
|
|
|
|
const jsmntok_t *routes;
|
|
|
|
#endif
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
|
|
|
|
info = tal(cmd, struct invoice_info);
|
|
|
|
info->cmd = cmd;
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2020-08-25 03:05:46 +02:00
|
|
|
p_req("msatoshi", param_positive_msat_or_any, &msatoshi_val),
|
2018-12-16 05:50:06 +01:00
|
|
|
p_req("label", param_label, &info->label),
|
|
|
|
p_req("description", param_escaped_string, &desc_val),
|
2019-04-10 06:58:24 +02:00
|
|
|
p_opt_def("expiry", param_time, &expiry, 3600*24*7),
|
2018-12-16 05:50:06 +01:00
|
|
|
p_opt("fallbacks", param_array, &fallbacks),
|
|
|
|
p_opt("preimage", param_tok, &preimagetok),
|
2019-12-17 07:18:13 +01:00
|
|
|
p_opt("exposeprivatechannels", param_chanhints,
|
|
|
|
&info->chanhints),
|
2019-01-15 05:00:27 +01:00
|
|
|
#if DEVELOPER
|
|
|
|
p_opt("dev-routes", param_array, &routes),
|
|
|
|
#endif
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2016-09-06 09:17:49 +02:00
|
|
|
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
if (strlen(info->label->s) > INVOICE_MAX_LABEL_LEN) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"Label '%s' over %u bytes", info->label->s,
|
|
|
|
INVOICE_MAX_LABEL_LEN);
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
2018-03-26 02:08:47 +02:00
|
|
|
|
|
|
|
if (strlen(desc_val) >= BOLT11_FIELD_BYTE_LIMIT) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"Descriptions greater than %d bytes "
|
|
|
|
"not yet supported "
|
|
|
|
"(description length %zu)",
|
|
|
|
BOLT11_FIELD_BYTE_LIMIT,
|
|
|
|
strlen(desc_val));
|
2018-02-17 12:48:22 +01:00
|
|
|
}
|
2017-11-21 07:26:15 +01:00
|
|
|
|
2019-02-21 01:45:57 +01:00
|
|
|
if (msatoshi_val
|
2019-02-21 04:45:54 +01:00
|
|
|
&& amount_msat_greater(*msatoshi_val, chainparams->max_payment)) {
|
2019-01-31 00:42:06 +01:00
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
2019-02-21 04:45:54 +01:00
|
|
|
"msatoshi cannot exceed %s",
|
|
|
|
type_to_string(tmpctx, struct amount_msat,
|
|
|
|
&chainparams->max_payment));
|
2019-01-31 00:42:06 +01:00
|
|
|
}
|
|
|
|
|
2018-04-05 07:13:51 +02:00
|
|
|
if (fallbacks) {
|
2019-01-17 03:12:13 +01:00
|
|
|
size_t i;
|
|
|
|
const jsmntok_t *t;
|
2018-04-05 07:13:51 +02:00
|
|
|
|
2019-01-17 03:12:13 +01:00
|
|
|
fallback_scripts = tal_arr(cmd, const u8 *, fallbacks->size);
|
|
|
|
json_for_each_arr(i, t, fallbacks) {
|
2018-12-16 05:52:06 +01:00
|
|
|
struct command_result *r;
|
2019-01-17 03:12:13 +01:00
|
|
|
|
|
|
|
r = parse_fallback(cmd, buffer, t, &fallback_scripts[i]);
|
2018-12-16 05:52:06 +01:00
|
|
|
if (r)
|
|
|
|
return r;
|
2018-04-05 07:13:51 +02:00
|
|
|
}
|
2018-02-15 00:45:04 +01:00
|
|
|
}
|
|
|
|
|
2018-04-22 15:42:23 +02:00
|
|
|
if (preimagetok) {
|
|
|
|
/* Get secret preimage from user. */
|
|
|
|
if (!hex_decode(buffer + preimagetok->start,
|
|
|
|
preimagetok->end - preimagetok->start,
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
&info->payment_preimage,
|
|
|
|
sizeof(info->payment_preimage))) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
|
|
"preimage must be 64 hex digits");
|
2018-04-22 15:42:23 +02:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
/* Generate random secret preimage. */
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
randombytes_buf(&info->payment_preimage,
|
|
|
|
sizeof(info->payment_preimage));
|
2018-04-22 15:42:23 +02:00
|
|
|
/* Generate preimage hash. */
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
sha256(&rhash, &info->payment_preimage, sizeof(info->payment_preimage));
|
2019-11-23 01:19:23 +01:00
|
|
|
/* Generate payment secret. */
|
|
|
|
invoice_secret(&info->payment_preimage, &payment_secret);
|
2018-04-25 01:04:33 +02:00
|
|
|
|
2019-02-21 03:38:35 +01:00
|
|
|
info->b11 = new_bolt11(info, msatoshi_val);
|
2019-01-31 00:42:06 +01:00
|
|
|
info->b11->chain = chainparams;
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
info->b11->timestamp = time_now().ts.tv_sec;
|
|
|
|
info->b11->payment_hash = rhash;
|
|
|
|
info->b11->receiver_id = cmd->ld->id;
|
|
|
|
info->b11->min_final_cltv_expiry = cmd->ld->config.cltv_final;
|
|
|
|
info->b11->expiry = *expiry;
|
|
|
|
info->b11->description = tal_steal(info->b11, desc_val);
|
|
|
|
info->b11->description_hash = NULL;
|
2019-11-23 01:19:23 +01:00
|
|
|
info->b11->payment_secret = tal_dup(info->b11, struct secret,
|
|
|
|
&payment_secret);
|
2020-04-02 06:04:47 +02:00
|
|
|
info->b11->features = tal_dup_talarr(info->b11, u8,
|
2020-04-03 02:03:59 +02:00
|
|
|
cmd->ld->our_features
|
2020-04-02 06:04:47 +02:00
|
|
|
->bits[BOLT11_FEATURE]);
|
2018-02-28 17:26:58 +01:00
|
|
|
|
2019-01-15 05:00:27 +01:00
|
|
|
#if DEVELOPER
|
|
|
|
info->b11->routes = unpack_routes(info->b11, buffer, routes);
|
2020-08-05 15:50:38 +02:00
|
|
|
#else
|
|
|
|
info->b11->routes = NULL;
|
2019-01-15 05:00:27 +01:00
|
|
|
#endif
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
if (fallback_scripts)
|
|
|
|
info->b11->fallbacks = tal_steal(info->b11, fallback_scripts);
|
2018-02-28 17:26:58 +01:00
|
|
|
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
subd_req(cmd, cmd->ld->gossip,
|
2020-08-25 04:05:45 +02:00
|
|
|
take(towire_gossipd_get_incoming_channels(NULL)),
|
json-invoice: add routeboost, warnings.
We split json_invoice(), as it now needs to round-trip to the gossipd,
and uniqueness checks need to happen *after* gossipd replies to avoid
a race.
For every candidate channel gossipd gives us, we check that it's in
state NORMAL (not shutting down, not still waiting for lockin), that
it's connected, and that it has capacity. We then choose one with
probability weighted by excess capacity, so larger channels are more
likely.
As a side effect of this, we can tell if an invoice is unpayble (no
channels have sufficient incoming capacity) or difficuly (no *online*
channels have sufficient capacity), so we add those warnings.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2018-09-27 07:29:17 +02:00
|
|
|
-1, 0, gossipd_incoming_channels_reply, info);
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_still_pending(cmd);
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
|
|
|
|
2017-01-04 04:38:15 +01:00
|
|
|
static const struct json_command invoice_command = {
|
2019-05-22 16:08:16 +02:00
|
|
|
"invoice",
|
|
|
|
"payment",
|
|
|
|
json_invoice,
|
|
|
|
"Create an invoice for {msatoshi} with {label} "
|
|
|
|
"and {description} with optional {expiry} seconds "
|
2019-07-25 06:37:16 +02:00
|
|
|
"(default 1 week), optional {fallbacks} address list"
|
2019-05-22 16:08:16 +02:00
|
|
|
"(default empty list) and optional {preimage} "
|
|
|
|
"(default autogenerated)"};
|
2017-01-04 04:38:15 +01:00
|
|
|
AUTODATA(json_command, &invoice_command);
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-10-19 03:17:49 +02:00
|
|
|
static void json_add_invoices(struct json_stream *response,
|
2018-01-14 15:15:30 +01:00
|
|
|
struct wallet *wallet,
|
2019-06-12 02:38:54 +02:00
|
|
|
const struct json_escape *label)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2018-02-24 13:11:14 +01:00
|
|
|
struct invoice_iterator it;
|
2018-07-27 12:57:02 +02:00
|
|
|
const struct invoice_details *details;
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-06-14 06:50:47 +02:00
|
|
|
/* Don't iterate entire db if we're just after one. */
|
|
|
|
if (label) {
|
|
|
|
struct invoice invoice;
|
|
|
|
if (wallet_invoice_find_by_label(wallet, &invoice, label)) {
|
2018-07-27 12:57:02 +02:00
|
|
|
details = wallet_invoice_details(response, wallet, invoice);
|
2019-06-12 02:38:54 +02:00
|
|
|
json_object_start(response, NULL);
|
2018-07-27 12:57:02 +02:00
|
|
|
json_add_invoice(response, details);
|
2019-06-12 02:38:54 +02:00
|
|
|
json_object_end(response);
|
2018-06-14 06:50:47 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-24 13:11:14 +01:00
|
|
|
memset(&it, 0, sizeof(it));
|
|
|
|
while (wallet_invoice_iterate(wallet, &it)) {
|
2018-07-27 12:57:02 +02:00
|
|
|
details = wallet_invoice_iterator_deref(response, wallet, &it);
|
2019-06-12 02:38:54 +02:00
|
|
|
json_object_start(response, NULL);
|
2018-07-27 12:57:02 +02:00
|
|
|
json_add_invoice(response, details);
|
2019-06-12 02:38:54 +02:00
|
|
|
json_object_end(response);
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_listinvoices(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2019-06-12 02:38:54 +02:00
|
|
|
struct json_escape *label;
|
2018-10-19 03:17:49 +02:00
|
|
|
struct json_stream *response;
|
2018-01-14 15:15:30 +01:00
|
|
|
struct wallet *wallet = cmd->ld->wallet;
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2018-12-16 05:50:06 +01:00
|
|
|
p_opt("label", param_label, &label),
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2018-10-19 03:17:48 +02:00
|
|
|
response = json_stream_success(cmd);
|
2018-07-29 04:08:29 +02:00
|
|
|
json_array_start(response, "invoices");
|
|
|
|
json_add_invoices(response, wallet, label);
|
2016-09-06 09:17:49 +02:00
|
|
|
json_array_end(response);
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_success(cmd, response);
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
|
|
|
|
2018-01-16 21:29:32 +01:00
|
|
|
static const struct json_command listinvoices_command = {
|
2018-01-16 21:28:46 +01:00
|
|
|
"listinvoices",
|
2019-05-22 16:08:16 +02:00
|
|
|
"payment",
|
2018-01-16 21:28:46 +01:00
|
|
|
json_listinvoices,
|
2018-01-22 09:55:07 +01:00
|
|
|
"Show invoice {label} (or all, if no {label})"
|
2018-01-16 21:28:46 +01:00
|
|
|
};
|
|
|
|
AUTODATA(json_command, &listinvoices_command);
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_delinvoice(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2018-02-23 02:04:47 +01:00
|
|
|
struct invoice i;
|
2018-07-27 12:57:02 +02:00
|
|
|
const struct invoice_details *details;
|
2018-10-19 03:17:49 +02:00
|
|
|
struct json_stream *response;
|
2018-03-26 02:08:16 +02:00
|
|
|
const char *status, *actual_status;
|
2019-06-12 02:38:54 +02:00
|
|
|
struct json_escape *label;
|
2018-01-14 15:15:30 +01:00
|
|
|
struct wallet *wallet = cmd->ld->wallet;
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2018-12-16 05:50:06 +01:00
|
|
|
p_req("label", param_label, &label),
|
|
|
|
p_req("status", param_string, &status),
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-02-23 02:04:47 +01:00
|
|
|
if (!wallet_invoice_find_by_label(wallet, &i, label)) {
|
2020-07-19 11:04:03 +02:00
|
|
|
return command_fail(cmd, INVOICE_NOT_FOUND, "Unknown invoice");
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
2018-07-27 12:57:02 +02:00
|
|
|
|
|
|
|
details = wallet_invoice_details(cmd, cmd->ld->wallet, i);
|
2017-10-05 23:29:56 +02:00
|
|
|
|
2018-01-18 04:57:16 +01:00
|
|
|
/* This is time-sensitive, so only call once; otherwise error msg
|
|
|
|
* might not make sense if it changed! */
|
2018-07-27 12:57:02 +02:00
|
|
|
actual_status = invoice_status_str(details);
|
2018-01-18 04:57:16 +01:00
|
|
|
if (!streq(actual_status, status)) {
|
2020-07-19 11:04:03 +02:00
|
|
|
struct json_stream *js;
|
|
|
|
js = json_stream_fail(cmd, INVOICE_STATUS_UNEXPECTED,
|
|
|
|
tal_fmt(tmpctx,
|
|
|
|
"Invoice status is %s not %s",
|
|
|
|
actual_status, status));
|
|
|
|
json_add_string(js, "current_status", actual_status);
|
|
|
|
json_add_string(js, "expected_status", status);
|
|
|
|
json_object_end(js);
|
|
|
|
return command_failed(cmd, js);
|
2018-01-18 04:57:16 +01:00
|
|
|
}
|
|
|
|
|
2018-01-18 04:55:43 +01:00
|
|
|
if (!wallet_invoice_delete(wallet, i)) {
|
|
|
|
log_broken(cmd->ld->log,
|
|
|
|
"Error attempting to remove invoice %"PRIu64,
|
2018-02-23 02:04:47 +01:00
|
|
|
i.id);
|
2020-07-19 11:04:03 +02:00
|
|
|
/* FIXME: allocate a generic DATABASE_ERROR code. */
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, LIGHTNINGD, "Database error");
|
2017-12-27 12:51:58 +01:00
|
|
|
}
|
|
|
|
|
2018-10-19 03:17:48 +02:00
|
|
|
response = json_stream_success(cmd);
|
|
|
|
json_add_invoice(response, details);
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_success(cmd, response);
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
|
|
|
|
2017-01-04 04:38:15 +01:00
|
|
|
static const struct json_command delinvoice_command = {
|
2016-09-06 09:17:49 +02:00
|
|
|
"delinvoice",
|
2019-05-22 16:08:16 +02:00
|
|
|
"payment",
|
2016-09-06 09:17:49 +02:00
|
|
|
json_delinvoice,
|
2018-01-18 04:57:16 +01:00
|
|
|
"Delete unpaid invoice {label} with {status}",
|
2016-09-06 09:17:49 +02:00
|
|
|
};
|
2017-01-04 04:38:15 +01:00
|
|
|
AUTODATA(json_command, &delinvoice_command);
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_delexpiredinvoice(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
2018-02-26 13:37:53 +01:00
|
|
|
{
|
2018-08-13 18:16:41 +02:00
|
|
|
u64 *maxexpirytime;
|
2018-02-26 13:37:53 +01:00
|
|
|
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2018-12-16 05:50:06 +01:00
|
|
|
p_opt_def("maxexpirytime", param_u64, &maxexpirytime,
|
2018-08-13 18:16:41 +02:00
|
|
|
time_now().ts.tv_sec),
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2018-02-26 13:37:53 +01:00
|
|
|
|
2018-08-13 18:16:41 +02:00
|
|
|
wallet_invoice_delete_expired(cmd->ld->wallet, *maxexpirytime);
|
2018-02-26 13:37:53 +01:00
|
|
|
|
2019-06-12 02:38:54 +02:00
|
|
|
return command_success(cmd, json_stream_success(cmd));
|
2018-02-26 13:37:53 +01:00
|
|
|
}
|
|
|
|
static const struct json_command delexpiredinvoice_command = {
|
|
|
|
"delexpiredinvoice",
|
2019-05-22 16:08:16 +02:00
|
|
|
"payment",
|
2018-02-26 13:37:53 +01:00
|
|
|
json_delexpiredinvoice,
|
|
|
|
"Delete all expired invoices that expired as of given {maxexpirytime} (a UNIX epoch time), or all expired invoices if not specified"
|
|
|
|
};
|
|
|
|
AUTODATA(json_command, &delexpiredinvoice_command);
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_waitanyinvoice(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
2016-09-06 09:17:49 +02:00
|
|
|
{
|
2018-08-13 18:16:41 +02:00
|
|
|
u64 *pay_index;
|
2020-01-28 02:30:00 +01:00
|
|
|
u64 *timeout;
|
2017-12-26 14:47:27 +01:00
|
|
|
struct wallet *wallet = cmd->ld->wallet;
|
2016-09-06 09:17:49 +02:00
|
|
|
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2018-12-16 05:50:06 +01:00
|
|
|
p_opt_def("lastpay_index", param_u64, &pay_index, 0),
|
2020-01-28 02:30:00 +01:00
|
|
|
p_opt("timeout", ¶m_u64, &timeout),
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2017-12-26 14:47:27 +01:00
|
|
|
|
2020-01-28 02:30:00 +01:00
|
|
|
/*~ We allocate the timeout and the wallet-waitanyinvoice
|
|
|
|
* in the cmd context, so whichever one manages to complete
|
|
|
|
* the command first (and destroy the cmd context)
|
|
|
|
* auto-cancels the other, is not tal amazing?
|
|
|
|
*/
|
|
|
|
if (timeout)
|
|
|
|
(void) new_reltimer(cmd->ld->timers, cmd,
|
|
|
|
time_from_sec(*timeout),
|
|
|
|
&wait_timed_out, cmd);
|
|
|
|
|
2018-01-14 15:15:30 +01:00
|
|
|
/* Set command as pending. We do not know if
|
|
|
|
* wallet_invoice_waitany will return immediately
|
|
|
|
* or not, so indicating pending is safest. */
|
2018-12-16 05:53:06 +01:00
|
|
|
fixme_ignore(command_still_pending(cmd));
|
2018-01-14 15:15:30 +01:00
|
|
|
|
|
|
|
/* Find next paid invoice. */
|
2018-08-13 18:16:41 +02:00
|
|
|
wallet_invoice_waitany(cmd, wallet, *pay_index,
|
2018-01-14 15:15:30 +01:00
|
|
|
&wait_on_invoice, (void*) cmd);
|
2018-12-16 05:52:06 +01:00
|
|
|
|
2018-12-17 04:52:08 +01:00
|
|
|
return command_its_complicated("wallet_invoice_waitany might complete"
|
|
|
|
" immediately, but we also call it as a"
|
|
|
|
" callback so plumbing through the return"
|
|
|
|
" is non-trivial.");
|
2016-09-06 09:17:49 +02:00
|
|
|
}
|
|
|
|
|
2017-01-17 22:09:09 +01:00
|
|
|
static const struct json_command waitanyinvoice_command = {
|
|
|
|
"waitanyinvoice",
|
2019-05-22 16:08:16 +02:00
|
|
|
"payment",
|
2017-01-17 22:09:09 +01:00
|
|
|
json_waitanyinvoice,
|
2020-01-28 02:30:00 +01:00
|
|
|
"Wait for the next invoice to be paid, after {lastpay_index} (if supplied). "
|
|
|
|
"If {timeout} seconds is reached while waiting, fail with an error."
|
2016-09-06 09:17:49 +02:00
|
|
|
};
|
2017-01-17 22:09:09 +01:00
|
|
|
AUTODATA(json_command, &waitanyinvoice_command);
|
2017-01-10 12:18:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* Wait for an incoming payment matching the `label` in the JSON
|
|
|
|
* command. This will either return immediately if the payment has
|
|
|
|
* already been received or it may add the `cmd` to the list of
|
|
|
|
* waiters, if the payment is still pending.
|
|
|
|
*/
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_waitinvoice(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
2017-01-10 12:18:40 +01:00
|
|
|
{
|
2018-02-23 02:04:47 +01:00
|
|
|
struct invoice i;
|
2018-07-27 12:57:02 +02:00
|
|
|
const struct invoice_details *details;
|
2018-01-14 15:15:30 +01:00
|
|
|
struct wallet *wallet = cmd->ld->wallet;
|
2019-06-12 02:38:54 +02:00
|
|
|
struct json_escape *label;
|
2017-01-10 12:18:40 +01:00
|
|
|
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2018-12-16 05:50:06 +01:00
|
|
|
p_req("label", param_label, &label),
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2017-01-10 12:18:40 +01:00
|
|
|
|
2018-02-23 02:04:47 +01:00
|
|
|
if (!wallet_invoice_find_by_label(wallet, &i, label)) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, LIGHTNINGD, "Label not found");
|
2018-02-20 02:07:30 +01:00
|
|
|
}
|
2018-07-27 12:57:02 +02:00
|
|
|
details = wallet_invoice_details(cmd, cmd->ld->wallet, i);
|
2018-02-20 02:07:30 +01:00
|
|
|
|
2018-02-23 02:04:47 +01:00
|
|
|
/* If paid or expired return immediately */
|
2018-07-27 12:57:02 +02:00
|
|
|
if (details->state == PAID || details->state == EXPIRED) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return tell_waiter(cmd, &i);
|
2017-10-03 18:31:07 +02:00
|
|
|
} else {
|
|
|
|
/* There is an unpaid one matching, let's wait... */
|
2018-12-16 05:53:06 +01:00
|
|
|
fixme_ignore(command_still_pending(cmd));
|
2018-01-14 15:15:30 +01:00
|
|
|
wallet_invoice_waitone(cmd, wallet, i,
|
|
|
|
&wait_on_invoice, (void *) cmd);
|
2018-12-17 04:52:08 +01:00
|
|
|
return command_its_complicated("wallet_invoice_waitone might"
|
|
|
|
" complete immediately");
|
2017-01-10 12:18:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 22:09:09 +01:00
|
|
|
static const struct json_command waitinvoice_command = {
|
|
|
|
"waitinvoice",
|
2019-05-22 16:08:16 +02:00
|
|
|
"payment",
|
2017-01-17 22:09:09 +01:00
|
|
|
json_waitinvoice,
|
2018-01-23 02:02:10 +01:00
|
|
|
"Wait for an incoming payment matching the invoice with {label}, or if the invoice expires"
|
2017-01-10 12:18:40 +01:00
|
|
|
};
|
2017-01-17 22:09:09 +01:00
|
|
|
AUTODATA(json_command, &waitinvoice_command);
|
2017-11-22 01:25:39 +01:00
|
|
|
|
2018-10-19 03:17:49 +02:00
|
|
|
static void json_add_fallback(struct json_stream *response,
|
2018-04-05 07:13:51 +02:00
|
|
|
const char *fieldname,
|
|
|
|
const u8 *fallback,
|
|
|
|
const struct chainparams *chain)
|
|
|
|
{
|
|
|
|
struct bitcoin_address pkh;
|
|
|
|
struct ripemd160 sh;
|
|
|
|
struct sha256 wsh;
|
|
|
|
|
|
|
|
json_object_start(response, fieldname);
|
|
|
|
if (is_p2pkh(fallback, &pkh)) {
|
|
|
|
json_add_string(response, "type", "P2PKH");
|
|
|
|
json_add_string(response, "addr",
|
2019-05-06 23:17:15 +02:00
|
|
|
bitcoin_to_base58(tmpctx, chain, &pkh));
|
2018-04-05 07:13:51 +02:00
|
|
|
} else if (is_p2sh(fallback, &sh)) {
|
|
|
|
json_add_string(response, "type", "P2SH");
|
|
|
|
json_add_string(response, "addr",
|
2019-05-06 23:17:15 +02:00
|
|
|
p2sh_to_base58(tmpctx, chain, &sh));
|
2018-04-05 07:13:51 +02:00
|
|
|
} else if (is_p2wpkh(fallback, &pkh)) {
|
|
|
|
char out[73 + strlen(chain->bip173_name)];
|
|
|
|
json_add_string(response, "type", "P2WPKH");
|
|
|
|
if (segwit_addr_encode(out, chain->bip173_name, 0,
|
|
|
|
(const u8 *)&pkh, sizeof(pkh)))
|
|
|
|
json_add_string(response, "addr", out);
|
|
|
|
} else if (is_p2wsh(fallback, &wsh)) {
|
|
|
|
char out[73 + strlen(chain->bip173_name)];
|
|
|
|
json_add_string(response, "type", "P2WSH");
|
|
|
|
if (segwit_addr_encode(out, chain->bip173_name, 0,
|
|
|
|
(const u8 *)&wsh, sizeof(wsh)))
|
|
|
|
json_add_string(response, "addr", out);
|
|
|
|
}
|
2018-07-28 07:53:33 +02:00
|
|
|
json_add_hex_talarr(response, "hex", fallback);
|
2018-04-05 07:13:51 +02:00
|
|
|
json_object_end(response);
|
|
|
|
}
|
|
|
|
|
2018-12-16 05:52:06 +01:00
|
|
|
static struct command_result *json_decodepay(struct command *cmd,
|
|
|
|
const char *buffer,
|
|
|
|
const jsmntok_t *obj UNNEEDED,
|
|
|
|
const jsmntok_t *params)
|
2017-11-22 01:25:39 +01:00
|
|
|
{
|
|
|
|
struct bolt11 *b11;
|
2018-10-19 03:17:49 +02:00
|
|
|
struct json_stream *response;
|
2018-10-19 03:17:48 +02:00
|
|
|
const char *str, *desc;
|
|
|
|
char *fail;
|
2017-11-22 01:25:39 +01:00
|
|
|
|
2018-07-16 22:48:38 +02:00
|
|
|
if (!param(cmd, buffer, params,
|
2018-12-16 05:50:06 +01:00
|
|
|
p_req("bolt11", param_string, &str),
|
|
|
|
p_opt("description", param_string, &desc),
|
2018-07-16 22:48:38 +02:00
|
|
|
NULL))
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_param_failed();
|
2017-11-22 01:25:39 +01:00
|
|
|
|
2020-04-03 02:03:59 +02:00
|
|
|
b11 = bolt11_decode(cmd, str, cmd->ld->our_features, desc, &fail);
|
2017-11-22 01:25:39 +01:00
|
|
|
|
|
|
|
if (!b11) {
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_fail(cmd, LIGHTNINGD, "Invalid bolt11: %s", fail);
|
2017-11-22 01:25:39 +01:00
|
|
|
}
|
|
|
|
|
2018-10-19 03:17:48 +02:00
|
|
|
response = json_stream_success(cmd);
|
2017-11-22 01:25:39 +01:00
|
|
|
json_add_string(response, "currency", b11->chain->bip173_name);
|
2018-01-19 10:53:24 +01:00
|
|
|
json_add_u64(response, "created_at", b11->timestamp);
|
2017-11-22 01:25:39 +01:00
|
|
|
json_add_u64(response, "expiry", b11->expiry);
|
2019-04-08 11:58:32 +02:00
|
|
|
json_add_node_id(response, "payee", &b11->receiver_id);
|
2019-02-21 03:38:35 +01:00
|
|
|
if (b11->msat)
|
2019-05-20 07:07:40 +02:00
|
|
|
json_add_amount_msat_compat(response, *b11->msat,
|
|
|
|
"msatoshi", "amount_msat");
|
2018-03-26 02:08:47 +02:00
|
|
|
if (b11->description) {
|
2019-06-12 02:38:54 +02:00
|
|
|
struct json_escape *esc = json_escape(NULL, b11->description);
|
2018-03-26 02:08:47 +02:00
|
|
|
json_add_escaped_string(response, "description", take(esc));
|
|
|
|
}
|
2017-11-22 01:25:39 +01:00
|
|
|
if (b11->description_hash)
|
2019-08-10 10:39:04 +02:00
|
|
|
json_add_sha256(response, "description_hash",
|
|
|
|
b11->description_hash);
|
2018-01-16 20:44:32 +01:00
|
|
|
json_add_num(response, "min_final_cltv_expiry",
|
|
|
|
b11->min_final_cltv_expiry);
|
2019-11-23 01:19:23 +01:00
|
|
|
if (b11->payment_secret)
|
|
|
|
json_add_secret(response, "payment_secret",
|
|
|
|
b11->payment_secret);
|
2019-09-05 03:07:16 +02:00
|
|
|
if (b11->features)
|
|
|
|
json_add_hex_talarr(response, "features", b11->features);
|
2018-04-05 07:13:51 +02:00
|
|
|
if (tal_count(b11->fallbacks)) {
|
|
|
|
json_array_start(response, "fallbacks");
|
|
|
|
for (size_t i = 0; i < tal_count(b11->fallbacks); i++)
|
|
|
|
json_add_fallback(response, NULL,
|
|
|
|
b11->fallbacks[i], b11->chain);
|
|
|
|
json_array_end(response);
|
2017-11-22 01:25:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tal_count(b11->routes)) {
|
|
|
|
size_t i, n;
|
|
|
|
|
|
|
|
json_array_start(response, "routes");
|
|
|
|
for (i = 0; i < tal_count(b11->routes); i++) {
|
|
|
|
json_array_start(response, NULL);
|
|
|
|
for (n = 0; n < tal_count(b11->routes[i]); n++) {
|
|
|
|
json_object_start(response, NULL);
|
2019-04-08 11:58:32 +02:00
|
|
|
json_add_node_id(response, "pubkey",
|
|
|
|
&b11->routes[i][n].pubkey);
|
2017-11-22 01:25:39 +01:00
|
|
|
json_add_short_channel_id(response,
|
|
|
|
"short_channel_id",
|
|
|
|
&b11->routes[i][n]
|
|
|
|
.short_channel_id);
|
2017-12-12 01:34:07 +01:00
|
|
|
json_add_u64(response, "fee_base_msat",
|
|
|
|
b11->routes[i][n].fee_base_msat);
|
|
|
|
json_add_u64(response, "fee_proportional_millionths",
|
|
|
|
b11->routes[i][n].fee_proportional_millionths);
|
2017-11-22 01:25:39 +01:00
|
|
|
json_add_num(response, "cltv_expiry_delta",
|
|
|
|
b11->routes[i][n]
|
|
|
|
.cltv_expiry_delta);
|
|
|
|
json_object_end(response);
|
|
|
|
}
|
|
|
|
json_array_end(response);
|
|
|
|
}
|
|
|
|
json_array_end(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!list_empty(&b11->extra_fields)) {
|
|
|
|
struct bolt11_field *extra;
|
|
|
|
|
|
|
|
json_array_start(response, "extra");
|
|
|
|
list_for_each(&b11->extra_fields, extra, list) {
|
2018-07-28 08:00:16 +02:00
|
|
|
char *data = tal_arr(cmd, char, tal_count(extra->data)+1);
|
2017-11-22 01:25:39 +01:00
|
|
|
size_t i;
|
|
|
|
|
2018-07-28 08:00:16 +02:00
|
|
|
for (i = 0; i < tal_count(extra->data); i++)
|
2017-11-22 01:25:39 +01:00
|
|
|
data[i] = bech32_charset[extra->data[i]];
|
|
|
|
data[i] = '\0';
|
|
|
|
json_object_start(response, NULL);
|
|
|
|
json_add_string(response, "tag",
|
|
|
|
tal_fmt(data, "%c", extra->tag));
|
|
|
|
json_add_string(response, "data", data);
|
|
|
|
tal_free(data);
|
|
|
|
json_object_end(response);
|
|
|
|
}
|
|
|
|
json_array_end(response);
|
|
|
|
}
|
|
|
|
|
2019-08-10 10:39:04 +02:00
|
|
|
json_add_sha256(response, "payment_hash", &b11->payment_hash);
|
2017-11-22 01:25:39 +01:00
|
|
|
|
|
|
|
json_add_string(response, "signature",
|
|
|
|
type_to_string(cmd, secp256k1_ecdsa_signature,
|
|
|
|
&b11->sig));
|
2018-12-16 05:52:06 +01:00
|
|
|
return command_success(cmd, response);
|
2017-11-22 01:25:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct json_command decodepay_command = {
|
|
|
|
"decodepay",
|
2019-05-22 16:08:16 +02:00
|
|
|
"payment",
|
2017-11-22 01:25:39 +01:00
|
|
|
json_decodepay,
|
2018-01-22 09:55:07 +01:00
|
|
|
"Decode {bolt11}, using {description} if necessary"
|
2017-11-22 01:25:39 +01:00
|
|
|
};
|
|
|
|
AUTODATA(json_command, &decodepay_command);
|