You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1586 lines
48 KiB

#include "invoice.h"
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/bolt11_json.h>
#include <common/bolt12.h>
#include <common/bolt12_merkle.h>
#include <common/configdir.h>
#include <common/features.h>
#include <common/json_command.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
#include <common/overflows.h>
#include <common/param.h>
#include <common/random_select.h>
#include <common/timeout.h>
#include <common/utils.h>
#include <errno.h>
#include <gossipd/gossipd_wiregen.h>
#include <hsmd/hsmd_wiregen.h>
#include <inttypes.h>
#include <lightningd/channel.h>
#include <lightningd/hsm_control.h>
#include <lightningd/json.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/notification.h>
#include <lightningd/options.h>
#include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h>
#include <lightningd/plugin_hook.h>
#include <lightningd/routehint.h>
#include <lightningd/subd.h>
#include <sodium/randombytes.h>
#include <wire/wire_sync.h>
static const char *invoice_status_str(const struct invoice_details *inv)
{
if (inv->state == PAID)
return "paid";
if (inv->state == EXPIRED)
return "expired";
return "unpaid";
}
static void json_add_invoice(struct json_stream *response,
const struct invoice_details *inv)
{
json_add_escaped_string(response, "label", inv->label);
json_add_invstring(response, inv->invstring);
json_add_sha256(response, "payment_hash", &inv->rhash);
if (inv->msat)
json_add_amount_msat_compat(response, *inv->msat,
"msatoshi", "amount_msat");
json_add_string(response, "status", invoice_status_str(inv));
if (inv->state == PAID) {
json_add_u64(response, "pay_index", inv->pay_index);
json_add_amount_msat_compat(response, inv->received,
"msatoshi_received",
"amount_received_msat");
json_add_u64(response, "paid_at", inv->paid_timestamp);
json_add_preimage(response, "payment_preimage", &inv->r);
}
if (inv->description)
json_add_string(response, "description", inv->description);
json_add_u64(response, "expires_at", inv->expiry_time);
if (inv->local_offer_id)
json_add_sha256(response, "local_offer_id", inv->local_offer_id);
}
static struct command_result *tell_waiter(struct command *cmd,
const struct invoice *inv)
{
struct json_stream *response;
const struct invoice_details *details;
details = wallet_invoice_details(cmd, cmd->ld->wallet, *inv);
if (details->state == PAID) {
response = json_stream_success(cmd);
json_add_invoice(response, details);
return command_success(cmd, response);
} else {
response = json_stream_fail(cmd, INVOICE_EXPIRED_DURING_WAIT,
"invoice expired during wait");
json_add_invoice(response, details);
json_object_end(response);
return command_failed(cmd, response);
}
}
static void tell_waiter_deleted(struct command *cmd)
{
was_pending(command_fail(cmd, LIGHTNINGD,
"Invoice deleted during wait"));
}
static void wait_on_invoice(const struct invoice *invoice, void *cmd)
{
if (invoice)
tell_waiter((struct command *) cmd, invoice);
else
tell_waiter_deleted((struct command *) cmd);
}
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"));
}
/* 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));
}
/* FIXME: This is a hack. The real secret should be a signature of some
* onion key, using the payer_id */
static void invoice_secret_bolt12(struct lightningd *ld,
const char *invstring,
struct secret *payment_secret)
{
char *fail;
struct tlv_invoice *inv;
struct sha256 merkle;
inv = invoice_decode(tmpctx, invstring, strlen(invstring),
NULL, NULL, &fail);
if (!inv) {
log_broken(ld->log, "Unable to decode our invoice %s",
invstring);
return;
}
merkle_tlv(inv->fields, &merkle);
BUILD_ASSERT(sizeof(*payment_secret) == sizeof(merkle));
memcpy(payment_secret, &merkle, sizeof(merkle));
}
struct invoice_payment_hook_payload {
struct lightningd *ld;
/* Set to NULL if it is deleted while waiting for plugin */
struct htlc_set *set;
/* What invoice it's trying to pay. */
const struct json_escape *label;
/* 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);
json_add_preimage(stream, "preimage", &payload->preimage);
json_add_string(stream, "msat",
type_to_string(tmpctx, struct amount_msat,
&payload->msat));
json_object_end(stream); /* .payment */
}
/* 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,
struct invoice_payment_hook_payload *payload)
{
assert(payload->set == set);
payload->set = NULL;
}
static const u8 *hook_gives_failmsg(const tal_t *ctx,
struct lightningd *ld,
const struct htlc_in *hin,
const char *buffer,
const jsmntok_t *toks)
{
const jsmntok_t *resulttok;
const jsmntok_t *t;
unsigned int val;
/* No plugin registered on hook at all? */
if (!buffer)
return NULL;
resulttok = json_get_member(buffer, toks, "result");
if (resulttok) {
if (json_tok_streq(buffer, resulttok, "continue")) {
return NULL;
} else if (json_tok_streq(buffer, resulttok, "reject")) {
return failmsg_incorrect_or_unknown(ctx, ld, hin);
} else
fatal("Invalid invoice_payment hook result: %.*s",
toks[0].end - toks[0].start, buffer);
}
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;
t = json_get_member(buffer, toks, "failure_code");
if (!t) {
static bool warned = false;
if (!warned) {
warned = true;
log_unusual(ld->log,
"Plugin did not return object with "
"'result' or 'failure_message' fields. "
"This is now deprecated and you should "
"return {'result': 'continue' } or "
"{'result': 'reject'} or "
"{'failure_message'... instead.");
}
return failmsg_incorrect_or_unknown(ctx, ld, hin);
}
if (!json_to_number(buffer, t, &val))
fatal("Invalid invoice_payment_hook failure_code: %.*s",
toks[0].end - toks[1].start, buffer);
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);
return failmsg_incorrect_or_unknown(ctx, ld, hin);
}
static void
invoice_payment_hooks_done(struct invoice_payment_hook_payload *payload STEALS)
{
struct invoice invoice;
struct lightningd *ld = payload->ld;
tal_del_destructor2(payload->set, invoice_payload_remove_set, payload);
/* We want to free this, whatever happens. */
tal_steal(tmpctx, payload);
/* 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)) {
htlc_set_fail(payload->set, take(failmsg_incorrect_or_unknown(
NULL, ld, payload->set->htlcs[0])));
return;
}
/* Paid or expired in the meantime. */
if (!wallet_invoice_resolve(ld->wallet, invoice, payload->msat)) {
htlc_set_fail(payload->set, take(failmsg_incorrect_or_unknown(
NULL, ld, payload->set->htlcs[0])));
return;
}
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));
htlc_set_fulfill(payload->set, &payload->preimage);
}
static bool
invoice_payment_deserialize(struct invoice_payment_hook_payload *payload,
const char *buffer,
const jsmntok_t *toks)
{
struct lightningd *ld = payload->ld;
const u8 *failmsg;
/* If peer dies or something, this can happen. */
if (!payload->set) {
log_debug(ld->log, "invoice '%s' paying htlc_in has gone!",
payload->label->s);
return false;
}
/* Did we have a hook result? */
failmsg = hook_gives_failmsg(NULL, ld,
payload->set->htlcs[0], buffer, toks);
if (failmsg) {
htlc_set_fail(payload->set, take(failmsg));
return false;
}
return true;
}
REGISTER_PLUGIN_HOOK(invoice_payment,
invoice_payment_deserialize,
invoice_payment_hooks_done,
invoice_payment_serialize,
struct invoice_payment_hook_payload *);
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)
{
struct invoice invoice;
const struct invoice_details *details;
/* 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.
*/
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));
}
return NULL;
}
details = wallet_invoice_details(ctx, ld->wallet, invoice);
/* BOLT #4:
* - 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.
*/
if (feature_is_set(details->features, COMPULSORY_FEATURE(OPT_VAR_ONION))
&& !payment_secret) {
log_debug(ld->log, "Attept to pay %s without secret",
type_to_string(tmpctx, struct sha256, &details->rhash));
return tal_free(details);
}
if (payment_secret) {
struct secret expected;
if (details->invstring && strstarts(details->invstring, "lni1"))
invoice_secret_bolt12(ld, details->invstring, &expected);
else
invoice_secret(&details->r, &expected);
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));
return tal_free(details);
}
}
/* 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;
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));
return tal_free(details);
}
if (amount_msat_add(&twice, *details->msat, *details->msat)
&& amount_msat_greater(msat, twice)) {
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));
/* BOLT #4:
*
* - if the amount paid is more than twice the amount
* expected:
* - SHOULD fail the HTLC.
*/
return tal_free(details);
}
}
return details;
}
void invoice_try_pay(struct lightningd *ld,
struct htlc_set *set,
const struct invoice_details *details)
{
struct invoice_payment_hook_payload *payload;
payload = tal(NULL, struct invoice_payment_hook_payload);
payload->ld = ld;
payload->label = tal_steal(payload, details->label);
payload->msat = set->so_far;
payload->preimage = details->r;
payload->set = set;
tal_add_destructor2(set, invoice_payload_remove_set, payload);
notify_invoice_payment(ld, payload->msat, payload->preimage, payload->label);
plugin_hook_call_invoice_payment(ld, payload);
}
static bool hsm_sign_b11(const u5 *u5bytes,
const u8 *hrpu8,
secp256k1_ecdsa_recoverable_signature *rsig,
struct lightningd *ld)
{
u8 *msg = towire_hsmd_sign_invoice(NULL, u5bytes, hrpu8);
if (!wire_sync_write(ld->hsm_fd, take(msg)))
fatal("Could not write to HSM: %s", strerror(errno));
msg = wire_sync_read(tmpctx, ld->hsm_fd);
if (!fromwire_hsmd_sign_invoice_reply(msg, rsig))
fatal("HSM gave bad sign_invoice_reply %s",
tal_hex(msg, msg));
return true;
}
static void hsm_sign_b12_invoice(struct lightningd *ld,
struct tlv_invoice *invoice)
{
struct sha256 merkle;
u8 *msg;
assert(!invoice->signature);
merkle_tlv(invoice->fields, &merkle);
msg = towire_hsmd_sign_bolt12(NULL, "invoice", "signature", &merkle, NULL);
if (!wire_sync_write(ld->hsm_fd, take(msg)))
fatal("Could not write to HSM: %s", strerror(errno));
msg = wire_sync_read(tmpctx, ld->hsm_fd);
invoice->signature = tal(invoice, struct bip340sig);
if (!fromwire_hsmd_sign_bolt12_reply(msg, invoice->signature))
fatal("HSM gave bad sign_invoice_reply %s",
tal_hex(msg, msg));
}
static struct command_result *parse_fallback(struct command *cmd,
const char *buffer,
const jsmntok_t *fallback,
const u8 **fallback_script)
{
enum address_parse_result fallback_parse;
fallback_parse
= json_to_address_scriptpubkey(cmd,
chainparams,
buffer, fallback,
fallback_script);
if (fallback_parse == ADDRESS_PARSE_UNRECOGNIZED) {
return command_fail(cmd, LIGHTNINGD,
"Fallback address not valid");
} else if (fallback_parse == ADDRESS_PARSE_WRONG_NETWORK) {
return command_fail(cmd, LIGHTNINGD,
"Fallback address does not match our network %s",
chainparams->network_name);
}
return NULL;
}
/*
* 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.
*/
static struct route_info **select_inchan(const tal_t *ctx,
struct lightningd *ld,
struct amount_msat amount_needed,
const struct routehint_candidate
*candidates)
{
/* BOLT11 struct wants an array of arrays (can provide multiple routes) */
struct route_info **r = NULL;
double total_weight = 0.0;
/* Collect suitable channels and assign each a weight. */
for (size_t i = 0; i < tal_count(candidates); i++) {
struct amount_msat excess, capacity;
struct amount_sat cumulative_reserve;
double excess_frac;
/* Does the peer have sufficient balance to pay us,
* even after having taken into account their reserve? */
if (!amount_msat_sub(&excess, candidates[i].capacity,
amount_needed))
continue;
/* 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 */
/* Find capacity and calculate its excess fraction */
if (!amount_sat_add(&cumulative_reserve,
candidates[i].c->our_config.channel_reserve,
candidates[i].c->channel_info.their_config.channel_reserve)
|| !amount_sat_to_msat(&capacity, candidates[i].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, candidates[i].c->scid));
continue;
}
/* We don't want a 0 probability if 0 excess; it might be the
* only one! So bump it by 1 msat */
if (!amount_msat_add(&excess, excess, AMOUNT_MSAT(1))) {
log_broken(ld->log, "Channel %s excess overflow!",
type_to_string(tmpctx,
struct short_channel_id,
candidates[i].c->scid));
continue;
}
excess_frac = amount_msat_ratio(excess, capacity);
if (random_select(excess_frac, &total_weight)) {
tal_free(r);
r = tal_arr(ctx, struct route_info *, 1);
r[0] = tal_dup(r, struct route_info, candidates[i].r);
}
}
return r;
}
static int cmp_rr_number(const struct routehint_candidate *a,
const struct routehint_candidate *b,
void *unused)
{
/* They're unique, so can't be equal */
if (a->c->rr_number > b->c->rr_number)
return 1;
assert(a->c->rr_number < b->c->rr_number);
return -1;
}
/** 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,
struct routehint_candidate
*candidates,
bool *warning_mpp_capacity)
{
/* The total amount we have gathered for incoming channels. */
struct amount_msat gathered;
/* Routehint array. */
struct route_info **routehints;
gathered = AMOUNT_MSAT(0);
routehints = tal_arr(ctx, struct route_info *, 0);
/* Sort by rr_number, so we get fresh channels. */
asort(candidates, tal_count(candidates), cmp_rr_number, NULL);
for (size_t i = 0; i < tal_count(candidates); i++) {
if (amount_msat_greater_eq(gathered, amount_needed))
break;
/* Add to current routehints set. */
if (!amount_msat_add(&gathered, gathered, candidates[i].capacity)) {
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,
&candidates[i].capacity));
continue;
}
tal_arr_expand(&routehints,
tal_dup(routehints, struct route_info,
candidates[i].r));
/* Put to the back of the round-robin list */
candidates[i].c->rr_number = ld->rr_counter++;
}
/* Check if we gathered enough. */
*warning_mpp_capacity = amount_msat_less(gathered, amount_needed);
return routehints;
}
/* Encapsulating struct while we wait for gossipd to give us incoming channels */
struct chanhints {
bool expose_all_private;
struct short_channel_id *hints;
};
struct invoice_info {
struct command *cmd;
struct preimage payment_preimage;
struct bolt11 *b11;
struct json_escape *label;
struct chanhints *chanhints;
};
static void gossipd_incoming_channels_reply(struct subd *gossipd,
const u8 *msg,
const int *fs,
struct invoice_info *info)
{
struct json_stream *response;
struct invoice invoice;
char *b11enc;
const struct invoice_details *details;
struct wallet *wallet = info->cmd->ld->wallet;
const struct chanhints *chanhints = info->chanhints;
struct routehint_candidate *candidates;
struct amount_msat offline_amt;
bool warning_mpp = false;
bool warning_mpp_capacity = false;
bool deadends;
bool node_unpublished;
candidates = routehint_candidates(tmpctx, info->cmd->ld, msg,
chanhints ? chanhints->expose_all_private : false,
chanhints ? chanhints->hints : NULL,
&node_unpublished,
&deadends,
&offline_amt);
/* If they told us to use scids and we couldn't, fail. */
if (tal_count(candidates) == 0
&& chanhints && 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;
}
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,
candidates);
/* 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,
candidates,
&warning_mpp_capacity);
warning_mpp = (tal_count(info->b11->routes) > 1);
}
}
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)) {
was_pending(command_fail(info->cmd,
INVOICE_PREIMAGE_ALREADY_EXISTS,
"preimage already used"));
return;
}
if (!wallet_invoice_create(wallet,
&invoice,
info->b11->msat,
info->label,
info->b11->expiry,
b11enc,
info->b11->description,
info->b11->features,
&info->payment_preimage,
&info->b11->payment_hash,
NULL)) {
was_pending(command_fail(info->cmd, INVOICE_LABEL_ALREADY_EXISTS,
"Duplicate label '%s'",
info->label->s));
return;
}
/* Get details */
details = wallet_invoice_details(info, wallet, invoice);
response = json_stream_success(info->cmd);
json_add_sha256(response, "payment_hash", &details->rhash);
json_add_u64(response, "expires_at", details->expiry_time);
json_add_string(response, "bolt11", details->invstring);
notify_invoice_creation(info->cmd->ld, info->b11->msat,
info->payment_preimage, info->label);
/* Warn if there's not sufficient incoming capacity. */
if (tal_count(info->b11->routes) == 0) {
log_unusual(info->cmd->ld->log,
"invoice: insufficient incoming capacity for %s%s",
info->b11->msat
? type_to_string(tmpctx, struct amount_msat,
info->b11->msat)
: "0",
amount_msat_greater(offline_amt, AMOUNT_MSAT(0))
? " (among currently connected peers)" : "");
if (amount_msat_greater(offline_amt, AMOUNT_MSAT(0))) {
json_add_string(response, "warning_offline",
"No channel with a peer that is currently connected"
" has sufficient incoming capacity");
} else if (deadends) {
json_add_string(response, "warning_deadends",
"No channel with a peer that is not a dead end");
} else if (tal_count(candidates) == 0) {
json_add_string(response, "warning_capacity",
"No channels");
} else {
json_add_string(response, "warning_capacity",
"No channel with a peer that has sufficient incoming capacity");
}
}
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.");
was_pending(command_success(info->cmd, response));
}
#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)
{
const jsmntok_t *t;
size_t i;
struct route_info *route = tal_arr(ctx, struct route_info, routetok->size);
json_for_each_arr(i, t, routetok) {
const jsmntok_t *pubkey, *fee_base, *fee_prop, *scid, *cltv;
struct route_info *r = &route[i];
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");
if (!json_to_node_id(buffer, pubkey, &r->pubkey)
|| !json_to_short_channel_id(buffer, scid,
&r->short_channel_id)
|| !json_to_number(buffer, fee_base, &r->fee_base_msat)
|| !json_to_number(buffer, fee_prop,
&r->fee_proportional_millionths)
|| !json_to_number(buffer, cltv, &cltv_u32))
abort();
/* We don't have a json_to_u16 */
r->cltv_expiry_delta = cltv_u32;
}
return route;
}
static struct route_info **unpack_routes(const tal_t *ctx,
const char *buffer,
const jsmntok_t *routestok)
{
struct route_info **routes;
const jsmntok_t *t;
size_t i;
if (!routestok)
return NULL;
routes = tal_arr(ctx, struct route_info *, routestok->size);
json_for_each_arr(i, t, routestok)
routes[i] = unpack_route(routes, buffer, t);
return routes;
}
#endif /* DEVELOPER */
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)
{
if (json_tok_streq(buffer, tok, "any")) {
*msat = NULL;
return NULL;
}
*msat = tal(cmd, struct amount_msat);
if (parse_amount_msat(*msat, buffer + tok->start, tok->end - tok->start)
&& !amount_msat_eq(**msat, AMOUNT_MSAT(0)))
return NULL;
return command_fail_badparam(cmd, name, buffer, tok,
"should be positive msat or 'any'");
}
/* 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_badparam(cmd, name, buffer, tok,
"value too large");
}
**secs *= mul;
return NULL;
}
return command_fail_badparam(cmd, name, buffer, tok,
"should be a number with optional {s,m,h,d,w} suffix");
}
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_badparam(cmd, name, buffer, t,
"should be a short channel id");
}
}
return NULL;
}
/* Otherwise should be a short_channel_id */
return param_short_channel_id(cmd, name, buffer, tok,
&(*chanhints)->hints);
}
static struct command_result *param_preimage(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct preimage **preimage)
{
*preimage = tal(cmd, struct preimage);
if (!hex_decode(buffer + tok->start, tok->end - tok->start,
*preimage, sizeof(**preimage)))
return command_fail_badparam(cmd, "preimage",
buffer, tok,
"should be 64 hex digits");
return NULL;
}
static struct command_result *json_invoice(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
const jsmntok_t *fallbacks;
struct amount_msat *msatoshi_val;
struct invoice_info *info;
const char *desc_val;
const u8 **fallback_scripts = NULL;
u64 *expiry;
struct sha256 rhash;
struct secret payment_secret;
struct preimage *preimage;
u32 *cltv;
#if DEVELOPER
const jsmntok_t *routes;
#endif
info = tal(cmd, struct invoice_info);
info->cmd = cmd;
if (!param(cmd, buffer, params,
p_req("msatoshi", param_positive_msat_or_any, &msatoshi_val),
p_req("label", param_label, &info->label),
p_req("description", param_escaped_string, &desc_val),
p_opt_def("expiry", param_time, &expiry, 3600*24*7),
p_opt("fallbacks", param_array, &fallbacks),
p_opt("preimage", param_preimage, &preimage),
p_opt("exposeprivatechannels", param_chanhints,
&info->chanhints),
p_opt_def("cltv", param_number, &cltv,
cmd->ld->config.cltv_final),
#if DEVELOPER
p_opt("dev-routes", param_array, &routes),
#endif
NULL))
return command_param_failed();
if (strlen(info->label->s) > INVOICE_MAX_LABEL_LEN) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Label '%s' over %u bytes", info->label->s,
INVOICE_MAX_LABEL_LEN);
}
if (strlen(desc_val) >= BOLT11_FIELD_BYTE_LIMIT) {
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));
}
if (msatoshi_val
&& amount_msat_greater(*msatoshi_val, chainparams->max_payment)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"msatoshi cannot exceed %s",
type_to_string(tmpctx, struct amount_msat,
&chainparams->max_payment));
}
if (fallbacks) {
size_t i;
const jsmntok_t *t;
fallback_scripts = tal_arr(cmd, const u8 *, fallbacks->size);
json_for_each_arr(i, t, fallbacks) {
struct command_result *r;
r = parse_fallback(cmd, buffer, t, &fallback_scripts[i]);
if (r)
return r;
}
}
if (preimage)
info->payment_preimage = *preimage;
else
/* Generate random secret preimage. */
randombytes_buf(&info->payment_preimage,
sizeof(info->payment_preimage));
/* Generate preimage hash. */
sha256(&rhash, &info->payment_preimage, sizeof(info->payment_preimage));
/* Generate payment secret. */
invoice_secret(&info->payment_preimage, &payment_secret);
info->b11 = new_bolt11(info, msatoshi_val);
info->b11->chain = chainparams;
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 = *cltv;
info->b11->expiry = *expiry;
info->b11->description = tal_steal(info->b11, desc_val);
info->b11->description_hash = NULL;
info->b11->payment_secret = tal_dup(info->b11, struct secret,
&payment_secret);
info->b11->features = tal_dup_talarr(info->b11, u8,
cmd->ld->our_features
->bits[BOLT11_FEATURE]);
#if DEVELOPER
info->b11->routes = unpack_routes(info->b11, buffer, routes);
#else
info->b11->routes = NULL;
#endif
if (fallback_scripts)
info->b11->fallbacks = tal_steal(info->b11, fallback_scripts);
subd_req(cmd, cmd->ld->gossip,
take(towire_gossipd_get_incoming_channels(NULL)),
-1, 0, gossipd_incoming_channels_reply, info);
return command_still_pending(cmd);
}
static const struct json_command invoice_command = {
"invoice",
"payment",
json_invoice,
"Create an invoice for {msatoshi} with {label} "
"and {description} with optional {expiry} seconds "
"(default 1 week), optional {fallbacks} address list"
"(default empty list) and optional {preimage} "
"(default autogenerated)"};
AUTODATA(json_command, &invoice_command);
static void json_add_invoices(struct json_stream *response,
struct wallet *wallet,
const struct json_escape *label,
const struct sha256 *payment_hash)
{
struct invoice_iterator it;
const struct invoice_details *details;
struct invoice invoice;
/* Don't iterate entire db if we're just after one. */
if (label) {
if (wallet_invoice_find_by_label(wallet, &invoice, label)) {
details =
wallet_invoice_details(response, wallet, invoice);
json_object_start(response, NULL);
json_add_invoice(response, details);
json_object_end(response);
}
} else if (payment_hash != NULL) {
if (wallet_invoice_find_by_rhash(wallet, &invoice,
payment_hash)) {
json_object_start(response, NULL);
json_add_invoice(
response,
wallet_invoice_details(response, wallet, invoice));
json_object_end(response);
}
} else {
memset(&it, 0, sizeof(it));
while (wallet_invoice_iterate(wallet, &it)) {
details = wallet_invoice_iterator_deref(response,
wallet, &it);
json_object_start(response, NULL);
json_add_invoice(response, details);
json_object_end(response);
}
}
}
static struct command_result *json_listinvoices(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct json_escape *label;
struct json_stream *response;
struct wallet *wallet = cmd->ld->wallet;
const char *invstring;
struct sha256 *payment_hash;
char *fail;
struct bolt11 *b11;
if (!param(cmd, buffer, params,
p_opt("label", param_label, &label),
p_opt("invstring", param_string, &invstring),
p_opt("payment_hash", param_sha256, &payment_hash),
NULL))
return command_param_failed();
if ((label && invstring) || (label && payment_hash) ||
(invstring && payment_hash)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Can only specify one of"
" {label}, {invstring} or {payment_hash}");
}
/* Extract the payment_hash from the invoice. */
if (invstring != NULL) {
b11 = bolt11_decode(cmd, invstring, cmd->ld->our_features, NULL,
NULL, &fail);
payment_hash = &b11->payment_hash;
}
response = json_stream_success(cmd);
json_array_start(response, "invoices");
json_add_invoices(response, wallet, label, payment_hash);
json_array_end(response);
return command_success(cmd, response);
}
static const struct json_command listinvoices_command = {
"listinvoices",
"payment",
json_listinvoices,
"Show invoice matching {label}, {invstring} or {payment_hash} (or all, if "
"no query parameter specified)"
};
AUTODATA(json_command, &listinvoices_command);
static struct command_result *json_delinvoice(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct invoice i;
const struct invoice_details *details;
struct json_stream *response;
const char *status, *actual_status;
struct json_escape *label;
struct wallet *wallet = cmd->ld->wallet;
if (!param(cmd, buffer, params,
p_req("label", param_label, &label),
p_req("status", param_string, &status),
NULL))
return command_param_failed();
if (!wallet_invoice_find_by_label(wallet, &i, label)) {
return command_fail(cmd, INVOICE_NOT_FOUND, "Unknown invoice");
}
details = wallet_invoice_details(cmd, cmd->ld->wallet, i);
/* This is time-sensitive, so only call once; otherwise error msg
* might not make sense if it changed! */
actual_status = invoice_status_str(details);
if (!streq(actual_status, status)) {
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);
}
if (!wallet_invoice_delete(wallet, i)) {
log_broken(cmd->ld->log,
"Error attempting to remove invoice %"PRIu64,
i.id);
/* FIXME: allocate a generic DATABASE_ERROR code. */
return command_fail(cmd, LIGHTNINGD, "Database error");
}
response = json_stream_success(cmd);
json_add_invoice(response, details);
return command_success(cmd, response);
}
static const struct json_command delinvoice_command = {
"delinvoice",
"payment",
json_delinvoice,
"Delete unpaid invoice {label} with {status}",
};
AUTODATA(json_command, &delinvoice_command);
static struct command_result *json_delexpiredinvoice(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
u64 *maxexpirytime;
if (!param(cmd, buffer, params,
p_opt_def("maxexpirytime", param_u64, &maxexpirytime,
time_now().ts.tv_sec),
NULL))
return command_param_failed();
wallet_invoice_delete_expired(cmd->ld->wallet, *maxexpirytime);
return command_success(cmd, json_stream_success(cmd));
}
static const struct json_command delexpiredinvoice_command = {
"delexpiredinvoice",
"payment",
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);
static struct command_result *json_waitanyinvoice(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
u64 *pay_index;
u64 *timeout;
struct wallet *wallet = cmd->ld->wallet;
if (!param(cmd, buffer, params,
p_opt_def("lastpay_index", param_u64, &pay_index, 0),
p_opt("timeout", &param_u64, &timeout),
NULL))
return command_param_failed();
/*~ 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);
/* Set command as pending. We do not know if
* wallet_invoice_waitany will return immediately
* or not, so indicating pending is safest. */
fixme_ignore(command_still_pending(cmd));
/* Find next paid invoice. */
wallet_invoice_waitany(cmd, wallet, *pay_index,
&wait_on_invoice, (void*) cmd);
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.");
}
static const struct json_command waitanyinvoice_command = {
"waitanyinvoice",
"payment",
json_waitanyinvoice,
"Wait for the next invoice to be paid, after {lastpay_index} (if supplied). "
"If {timeout} seconds is reached while waiting, fail with an error."
};
AUTODATA(json_command, &waitanyinvoice_command);
/* 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.
*/
static struct command_result *json_waitinvoice(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct invoice i;
const struct invoice_details *details;
struct wallet *wallet = cmd->ld->wallet;
struct json_escape *label;
if (!param(cmd, buffer, params,
p_req("label", param_label, &label),
NULL))
return command_param_failed();
if (!wallet_invoice_find_by_label(wallet, &i, label)) {
return command_fail(cmd, LIGHTNINGD, "Label not found");
}
details = wallet_invoice_details(cmd, cmd->ld->wallet, i);
/* If paid or expired return immediately */
if (details->state == PAID || details->state == EXPIRED) {
return tell_waiter(cmd, &i);
} else {
/* There is an unpaid one matching, let's wait... */
fixme_ignore(command_still_pending(cmd));
wallet_invoice_waitone(cmd, wallet, i,
&wait_on_invoice, (void *) cmd);
return command_its_complicated("wallet_invoice_waitone might"
" complete immediately");
}
}
static const struct json_command waitinvoice_command = {
"waitinvoice",
"payment",
json_waitinvoice,
"Wait for an incoming payment matching the invoice with {label}, or if the invoice expires"
};
AUTODATA(json_command, &waitinvoice_command);
static struct command_result *json_decodepay(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct bolt11 *b11;
struct json_stream *response;
const char *str, *desc;
char *fail;
if (!param(cmd, buffer, params,
p_req("bolt11", param_string, &str),
p_opt("description", param_string, &desc),
NULL))
return command_param_failed();
b11 = bolt11_decode(cmd, str, cmd->ld->our_features, desc, NULL,
&fail);
if (!b11) {
return command_fail(cmd, LIGHTNINGD, "Invalid bolt11: %s", fail);
}
response = json_stream_success(cmd);
json_add_bolt11(response, b11);
return command_success(cmd, response);
}
static const struct json_command decodepay_command = {
"decodepay",
"payment",
json_decodepay,
"Decode {bolt11}, using {description} if necessary"
};
AUTODATA(json_command, &decodepay_command);
/* If we fail because it exists, we also return the clashing invoice */
static struct command_result *fail_exists(struct command *cmd,
const struct json_escape *label)
{
struct json_stream *data;
struct invoice invoice;
struct wallet *wallet = cmd->ld->wallet;
data = json_stream_fail(cmd, INVOICE_LABEL_ALREADY_EXISTS,
"Duplicate label");
if (!wallet_invoice_find_by_label(wallet, &invoice, label))
fatal("Duplicate invoice %s not found any more?",
label->s);
json_add_invoice(data, wallet_invoice_details(cmd, wallet, invoice));
json_object_end(data);
return command_failed(cmd, data);
}
static struct command_result *json_createinvoice(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
const char *invstring;
struct json_escape *label;
struct preimage *preimage;
struct invoice invoice;
struct sha256 payment_hash;
struct json_stream *response;
struct bolt11 *b11;
struct sha256 hash;
u5 *sig;
bool have_n;
char *fail;
if (!param(cmd, buffer, params,
p_req("invstring", param_string, &invstring),
p_req("label", param_label, &label),
p_req("preimage", param_preimage, &preimage),
NULL))
return command_param_failed();
sha256(&payment_hash, preimage, sizeof(*preimage));
b11 = bolt11_decode_nosig(cmd, invstring, cmd->ld->our_features,
NULL, chainparams, &hash, &sig, &have_n,
&fail);
if (b11) {
/* This adds the signature */
char *b11enc = bolt11_encode(cmd, b11, have_n,
hsm_sign_b11, cmd->ld);
if (!b11->description)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Missing description in invoice");
if (!b11->expiry)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Missing expiry in invoice");
if (!sha256_eq(&payment_hash, &b11->payment_hash))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Incorrect preimage");
if (!wallet_invoice_create(cmd->ld->wallet,
&invoice,
b11->msat,
label,
b11->expiry,
b11enc,
b11->description,
b11->features,
preimage,
&payment_hash,
NULL))
return fail_exists(cmd, label);
notify_invoice_creation(cmd->ld, b11->msat, *preimage, label);
} else {
struct tlv_invoice *inv;
struct sha256 *local_offer_id;
inv = invoice_decode_nosig(cmd, invstring, strlen(invstring),
cmd->ld->our_features, chainparams,
&fail);
if (inv) {
char *b12enc;
struct amount_msat msat;
const char *desc;
u32 expiry;
enum offer_status status;
if (inv->signature)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"invoice already signed");
hsm_sign_b12_invoice(cmd->ld, inv);
b12enc = invoice_encode(cmd, inv);
if (inv->offer_id
&& wallet_offer_find(tmpctx, cmd->ld->wallet,
inv->offer_id, NULL, &status)) {
if (!offer_status_active(status))
return command_fail(cmd, INVOICE_OFFER_INACTIVE,
"offer not active");
local_offer_id = inv->offer_id;
} else
local_offer_id = NULL;
if (inv->amount)
msat = amount_msat(*inv->amount);
if (inv->relative_expiry)
expiry = *inv->relative_expiry;
else
expiry = BOLT12_DEFAULT_REL_EXPIRY;
if (!inv->payment_hash)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Missing payment_hash in invoice");
if (!sha256_eq(&payment_hash, inv->payment_hash))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Incorrect preimage");
if (!inv->description)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Missing description in invoice");
desc = tal_strndup(cmd,
cast_signed(char *, inv->description),
tal_bytelen(inv->description));
if (!wallet_invoice_create(cmd->ld->wallet,
&invoice,
inv->amount ? &msat : NULL,
label,
expiry,
b12enc,
desc,
inv->features,
preimage,
&payment_hash,
local_offer_id))
return fail_exists(cmd, label);
notify_invoice_creation(cmd->ld,
inv->amount ? &msat : NULL,
*preimage, label);
} else
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Unparsable invoice '%s': %s",
invstring, fail);
}
response = json_stream_success(cmd);
json_add_invoice(response,
wallet_invoice_details(cmd, cmd->ld->wallet, invoice));
return command_success(cmd, response);
}
static const struct json_command createinvoice_command = {
"createinvoice",
"payment",
json_createinvoice,
"Lowlevel command to sign and create invoice {invstring}, resolved with {preimage}, using unique {label}."
};
AUTODATA(json_command, &createinvoice_command);