mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-02 12:44:26 +01:00
plugins/pay: allow bolt12 invoices (EXPERIMENTAL_FEATURES).
Note that we remove the redundant "is this the correct chain?"
check, since bolt11_decode and bolt12_decode do that internally
anyway (this was changed in 924cc04bd2).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
a33e39b7e8
commit
9fe612db20
@@ -1,6 +1,10 @@
|
||||
PLUGIN_PAY_SRC := plugins/pay.c
|
||||
PLUGIN_PAY_OBJS := $(PLUGIN_PAY_SRC:.c=.o)
|
||||
|
||||
ifeq ($(EXPERIMENTAL_FEATURES),1)
|
||||
PLUGIN_PAY_EXPERIMENTAL_OBJS := common/bolt12.o common/bolt12_merkle.o wire/bolt12_exp_wiregen.o bitcoin/block.o
|
||||
endif
|
||||
|
||||
PLUGIN_AUTOCLEAN_SRC := plugins/autoclean.c
|
||||
PLUGIN_AUTOCLEAN_OBJS := $(PLUGIN_AUTOCLEAN_SRC:.c=.o)
|
||||
|
||||
@@ -104,7 +108,7 @@ PLUGIN_COMMON_OBJS := \
|
||||
wire/tlvstream.o \
|
||||
wire/towire.o
|
||||
|
||||
plugins/pay: bitcoin/chainparams.o $(PLUGIN_PAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/route.o common/dijkstra.o
|
||||
plugins/pay: bitcoin/chainparams.o $(PLUGIN_PAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/route.o common/dijkstra.o $(PLUGIN_PAY_EXPERIMENTAL_OBJS)
|
||||
$(PLUGIN_PAY_OBJS): $(PLUGIN_PAY_LIB_HEADER)
|
||||
|
||||
plugins/autoclean: bitcoin/chainparams.o $(PLUGIN_AUTOCLEAN_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS)
|
||||
|
||||
127
plugins/pay.c
127
plugins/pay.c
@@ -9,9 +9,14 @@
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/amount.h>
|
||||
#include <common/bolt11.h>
|
||||
#if EXPERIMENTAL_FEATURES
|
||||
#include <common/bolt12.h>
|
||||
#include <common/bolt12_merkle.h>
|
||||
#endif
|
||||
#include <common/errcode.h>
|
||||
#include <common/features.h>
|
||||
#include <common/gossip_constants.h>
|
||||
#include <common/gossmap.h>
|
||||
#include <common/json_stream.h>
|
||||
#include <common/pseudorand.h>
|
||||
#include <common/type_to_string.h>
|
||||
@@ -1881,7 +1886,7 @@ static struct command_result *json_listpays(struct command *cmd,
|
||||
|
||||
/* FIXME: would be nice to parse as a bolt11 so check worked in future */
|
||||
if (!param(cmd, buf, params,
|
||||
/* FIXME: paramter should be invstring now */
|
||||
/* FIXME: parameter should be invstring now */
|
||||
p_opt("bolt11", param_string, &invstring),
|
||||
p_opt("payment_hash", param_sha256, &payment_hash),
|
||||
NULL))
|
||||
@@ -1962,8 +1967,11 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
unsigned int *retryfor;
|
||||
u64 *riskfactor_millionths;
|
||||
struct shadow_route_data *shadow_route;
|
||||
struct amount_msat *invmsat;
|
||||
u64 invexpiry;
|
||||
#if EXPERIMENTAL_FEATURES
|
||||
struct sha256 *local_offer_id;
|
||||
const struct tlv_invoice *b12;
|
||||
#endif
|
||||
#if DEVELOPER
|
||||
bool *use_shadow;
|
||||
@@ -1972,7 +1980,9 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
/* If any of the modifiers need to add params to the JSON-RPC call we
|
||||
* would add them to the `param()` call below, and have them be
|
||||
* initialized directly that way. */
|
||||
if (!param(cmd, buf, params, p_req("bolt11", param_string, &b11str),
|
||||
if (!param(cmd, buf, params,
|
||||
/* FIXME: parameter should be invstring now */
|
||||
p_req("bolt11", param_string, &b11str),
|
||||
p_opt("msatoshi", param_msat, &msat),
|
||||
p_opt("label", param_string, &label),
|
||||
p_opt_def("riskfactor", param_millionths,
|
||||
@@ -1993,28 +2003,104 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
return command_param_failed();
|
||||
|
||||
p = payment_new(cmd, cmd, NULL /* No parent */, paymod_mods);
|
||||
p->invstring = tal_steal(p, b11str);
|
||||
|
||||
b11 = bolt11_decode(cmd, b11str, plugin_feature_set(cmd->plugin),
|
||||
NULL, chainparams, &fail);
|
||||
if (!b11)
|
||||
if (b11) {
|
||||
invmsat = b11->msat;
|
||||
invexpiry = b11->timestamp + b11->expiry;
|
||||
|
||||
p->destination = tal_dup(p, struct node_id, &b11->receiver_id);
|
||||
p->destination_has_tlv = feature_offered(b11->features,
|
||||
OPT_VAR_ONION);
|
||||
p->payment_hash = tal_dup(p, struct sha256, &b11->payment_hash);
|
||||
p->payment_secret = b11->payment_secret
|
||||
? tal_dup(p, struct secret, b11->payment_secret)
|
||||
: NULL;
|
||||
p->routes = tal_steal(p, b11->routes);
|
||||
p->min_final_cltv_expiry = b11->min_final_cltv_expiry;
|
||||
p->features = tal_steal(p, b11->features);
|
||||
/* Sanity check */
|
||||
if (feature_offered(b11->features, OPT_VAR_ONION)
|
||||
&& !b11->payment_secret)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Invalid bolt11:"
|
||||
" sets feature var_onion with no secret");
|
||||
#if EXPERIMENTAL_FEATURES
|
||||
} else if ((b12 = invoice_decode(cmd, b11str, strlen(b11str),
|
||||
plugin_feature_set(cmd->plugin),
|
||||
chainparams, &fail)) != NULL) {
|
||||
p->features = tal_steal(p, b12->features);
|
||||
|
||||
if (!b12->node_id)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"invoice missing node_id");
|
||||
if (!b12->payment_hash)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"invoice missing payment_hash");
|
||||
if (!b12->timestamp)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"invoice missing timestamp");
|
||||
if (b12->amount) {
|
||||
invmsat = tal(cmd, struct amount_msat);
|
||||
*invmsat = amount_msat(*b12->amount);
|
||||
} else
|
||||
invmsat = NULL;
|
||||
|
||||
/* FIXME: gossmap should store as pubkey32 */
|
||||
p->destination = tal(p, struct node_id);
|
||||
gossmap_guess_node_id(get_gossmap(cmd->plugin),
|
||||
b12->node_id,
|
||||
p->destination);
|
||||
p->destination_has_tlv = true;
|
||||
p->payment_hash = tal_dup(p, struct sha256, b12->payment_hash);
|
||||
if (b12->recurrence_counter && !label)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"recurring invoice requires a label");
|
||||
/* FIXME payment_secret should be signature! */
|
||||
{
|
||||
struct sha256 merkle;
|
||||
|
||||
p->payment_secret = tal(p, struct secret);
|
||||
merkle_tlv(b12->fields, &merkle);
|
||||
memcpy(p->payment_secret, &merkle, sizeof(merkle));
|
||||
BUILD_ASSERT(sizeof(*p->payment_secret) == sizeof(merkle));
|
||||
}
|
||||
p->routes = NULL;
|
||||
/* FIXME: paths! */
|
||||
if (b12->cltv)
|
||||
p->min_final_cltv_expiry = *b12->cltv;
|
||||
else
|
||||
p->min_final_cltv_expiry = 18;
|
||||
/* BOLT-offers #12:
|
||||
* - if `relative_expiry` is present:
|
||||
* - MUST reject the invoice if the current time since
|
||||
* 1970-01-01 UTC is greater than `timestamp` plus
|
||||
* `seconds_from_timestamp`.
|
||||
* - otherwise:
|
||||
* - MUST reject the invoice if the current time since
|
||||
* 1970-01-01 UTC is greater than `timestamp` plus 7200.
|
||||
*/
|
||||
if (b12->relative_expiry)
|
||||
invexpiry = *b12->timestamp + *b12->relative_expiry;
|
||||
else
|
||||
invexpiry = *b12->timestamp + 7200;
|
||||
p->local_offer_id = tal_steal(p, local_offer_id);
|
||||
#endif /* EXPERIMENTAL_FEATURES */
|
||||
} else
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Invalid bolt11: %s", fail);
|
||||
|
||||
if (!b11->chain)
|
||||
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "Invoice is for an unknown network");
|
||||
|
||||
if (b11->chain != chainparams)
|
||||
return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "Invoice is for another network %s", b11->chain->network_name);
|
||||
|
||||
if (time_now().ts.tv_sec > b11->timestamp + b11->expiry)
|
||||
if (time_now().ts.tv_sec > invexpiry)
|
||||
return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired");
|
||||
|
||||
if (b11->msat) {
|
||||
if (invmsat) {
|
||||
if (msat) {
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"msatoshi parameter unnecessary");
|
||||
}
|
||||
p->amount = *b11->msat;
|
||||
p->amount = *invmsat;
|
||||
|
||||
} else {
|
||||
if (!msat) {
|
||||
@@ -2024,26 +2110,9 @@ static struct command_result *json_paymod(struct command *cmd,
|
||||
p->amount = *msat;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
if (feature_offered(b11->features, OPT_VAR_ONION)
|
||||
&& !b11->payment_secret)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Invalid bolt11:"
|
||||
" sets feature var_onion with no secret");
|
||||
|
||||
p->local_id = &my_id;
|
||||
p->json_buffer = tal_steal(p, buf);
|
||||
p->json_toks = params;
|
||||
p->destination = tal_dup(p, struct node_id, &b11->receiver_id);
|
||||
p->destination_has_tlv = feature_offered(b11->features, OPT_VAR_ONION);
|
||||
p->payment_hash = tal_dup(p, struct sha256, &b11->payment_hash);
|
||||
p->payment_secret = b11->payment_secret
|
||||
? tal_dup(p, struct secret, b11->payment_secret)
|
||||
: NULL;
|
||||
p->routes = tal_steal(p, b11->routes);
|
||||
p->min_final_cltv_expiry = b11->min_final_cltv_expiry;
|
||||
p->features = tal_steal(p, b11->features);
|
||||
p->invstring = tal_steal(p, b11str);
|
||||
p->why = "Initial attempt";
|
||||
p->constraints.cltv_budget = *maxdelay;
|
||||
p->deadline = timeabs_add(time_now(), time_from_sec(*retryfor));
|
||||
|
||||
Reference in New Issue
Block a user