pay: Do not clobber error messages if we fail decoding a bolt11

We were automatically falling back to bolt12 decoding, clobbering the
fail message. Ultimately resulting in confusing error
messages (expected prefix lni but got lnbtrc). Now we first determine
which decoding we're trying to do, and then only decode accordingly.

Changelog-Fixed: pay: Report the correct decoding error if bolt11 parsing fails.
This commit is contained in:
Christian Decker 2021-03-02 13:12:05 +01:00 committed by Rusty Russell
parent ea92466025
commit 40e9d60ce0

View file

@ -1973,6 +1973,7 @@ static struct command_result *json_paymod(struct command *cmd,
u64 invexpiry;
struct sha256 *local_offer_id;
const struct tlv_invoice *b12;
bool is_b12;
#if DEVELOPER
bool *use_shadow;
#endif
@ -2003,31 +2004,45 @@ static struct command_result *json_paymod(struct command *cmd,
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) {
is_b12 = strlen(b11str) > 3 &&
(strstarts(b11str, "lni") || strstarts(b11str, "lno") ||
strstarts(b11str, "lnr"));
b11 = bolt11_decode(cmd, b11str, plugin_feature_set(cmd->plugin), NULL,
chainparams, &fail);
if (!is_b12) {
if (b11 == NULL)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11: %s", fail);
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->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
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)
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");
} else {
b12 = invoice_decode(cmd, b11str, strlen(b11str),
plugin_feature_set(cmd->plugin),
chainparams, &fail);
if (b12 == NULL)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11:"
" sets feature var_onion with no secret");
} else if ((b12 = invoice_decode(cmd, b11str, strlen(b11str),
plugin_feature_set(cmd->plugin),
chainparams, &fail)) != NULL) {
"Invalid bolt12: %s", fail);
if (!exp_offers)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"experimental-offers disabled");
@ -2051,14 +2066,14 @@ static struct command_result *json_paymod(struct command *cmd,
/* FIXME: gossmap should store as pubkey32 */
p->destination = tal(p, struct node_id);
gossmap_guess_node_id(get_gossmap(cmd->plugin),
b12->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");
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"recurring invoice requires a label");
/* FIXME payment_secret should be signature! */
{
struct sha256 merkle;
@ -2066,7 +2081,8 @@ static struct command_result *json_paymod(struct command *cmd,
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));
BUILD_ASSERT(sizeof(*p->payment_secret) ==
sizeof(merkle));
}
p->routes = NULL;
/* FIXME: paths! */
@ -2081,16 +2097,15 @@ static struct command_result *json_paymod(struct command *cmd,
* `seconds_from_timestamp`.
* - otherwise:
* - MUST reject the invoice if the current time since
* 1970-01-01 UTC is greater than `timestamp` plus 7200.
* 1970-01-01 UTC is greater than `timestamp` plus
* 7200.
*/
if (b12->relative_expiry)
invexpiry = *b12->timestamp + *b12->relative_expiry;
else
invexpiry = *b12->timestamp + BOLT12_DEFAULT_REL_EXPIRY;
p->local_offer_id = tal_steal(p, local_offer_id);
} else
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11: %s", fail);
}
if (time_now().ts.tv_sec > invexpiry)
return command_fail(cmd, PAY_INVOICE_EXPIRED, "Invoice expired");