Browse Source

invoice: allow numeric labels again.

Fixes: #1291
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
a85ead7058
  1. 8
      doc/lightning-invoice.7
  2. 7
      doc/lightning-invoice.7.txt
  3. 2
      external/libwally-core
  4. 39
      lightningd/invoice.c
  5. 23
      tests/test_lightningd.py

8
doc/lightning-invoice.7

@ -2,12 +2,12 @@
.\" Title: lightning-invoice .\" Title: lightning-invoice
.\" Author: [see the "AUTHOR" section] .\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 01/16/2018 .\" Date: 03/28/2018
.\" Manual: \ \& .\" Manual: \ \&
.\" Source: \ \& .\" Source: \ \&
.\" Language: English .\" Language: English
.\" .\"
.TH "LIGHTNING\-INVOICE" "7" "01/16/2018" "\ \&" "\ \&" .TH "LIGHTNING\-INVOICE" "7" "03/28/2018" "\ \&" "\ \&"
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
.\" * Define some portability stuff .\" * Define some portability stuff
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
@ -38,9 +38,9 @@ The \fBinvoice\fR RPC command creates the expectation of a payment of a given am
.sp .sp
The \fImsatoshi\fR can be the string "any", which creates an invoice that can be paid with any amount\&. The \fImsatoshi\fR can be the string "any", which creates an invoice that can be paid with any amount\&.
.sp .sp
The \fIlabel\fR must be unique; it is never revealed to other nodes on the lightning network, but it can be used to query the status of this invoice\&. The \fIlabel\fR must be a unique string or number (which is treated as a string, so "01" is different from "1"); it is never revealed to other nodes on the lightning network, but it can be used to query the status of this invoice\&.
.sp .sp
The \fIdescription\fR is a short description of purpose of payment, e\&.g\&. \fI1 cup of coffee\fR\&. This value is encoded into the BOLT11 invoice and is viewable by any node you send this invoice to\&. The \fIdescription\fR is a short description of purpose of payment, e\&.g\&. \fI1 cup of coffee\fR\&. This value is encoded into the BOLT11 invoice and is viewable by any node you send this invoice to\&. It must be UTF\-8, and cannot use \fI\eu\fR JSON escape codes\&.
.sp .sp
The \fIexpiry\fR is optionally the number of seconds the invoice is valid for\&. If no value is provided the default of 3600 (1 Hour) is used\&. The \fIexpiry\fR is optionally the number of seconds the invoice is valid for\&. If no value is provided the default of 3600 (1 Hour) is used\&.
.SH "RETURN VALUE" .SH "RETURN VALUE"

7
doc/lightning-invoice.7.txt

@ -19,9 +19,10 @@ lightning daemon can use to pay this invoice.
The 'msatoshi' can be the string "any", which creates an invoice The 'msatoshi' can be the string "any", which creates an invoice
that can be paid with any amount. that can be paid with any amount.
The 'label' must be a unique string; it is never revealed to other nodes on The 'label' must be a unique string or number (which is treated as a
the lightning network, but it can be used to query the status of this string, so "01" is different from "1"); it is never revealed to other
invoice. nodes on the lightning network, but it can be used to query the status
of this invoice.
The 'description' is a short description of purpose of payment, The 'description' is a short description of purpose of payment,
e.g. '1 cup of coffee'. This value is encoded into the BOLT11 invoice e.g. '1 cup of coffee'. This value is encoded into the BOLT11 invoice

2
external/libwally-core

@ -1 +1 @@
Subproject commit 8e6d990b5e62ff4d1c9bc68af29423cc98a232fa Subproject commit 770c572db76e7730dd2c8481c78aaf02682b1c1a

39
lightningd/invoice.c

@ -104,6 +104,29 @@ static bool hsm_sign_b11(const u5 *u5bytes,
return true; return true;
} }
/* We allow a string, or a literal number, for labels */
static struct json_escaped *json_tok_label(const tal_t *ctx,
const char *buffer,
const jsmntok_t *tok)
{
struct json_escaped *label;
label = json_tok_escaped_string(ctx, buffer, tok);
if (label)
return label;
/* Allow literal numbers */
if (tok->type != JSMN_PRIMITIVE)
return NULL;
for (int i = tok->start; i < tok->end; i++)
if (!cisdigit(buffer[i]))
return NULL;
return json_escaped_string_(ctx, buffer + tok->start,
tok->end - tok->start);
}
static void json_invoice(struct command *cmd, static void json_invoice(struct command *cmd,
const char *buffer, const jsmntok_t *params) const char *buffer, const jsmntok_t *params)
{ {
@ -148,9 +171,9 @@ static void json_invoice(struct command *cmd,
} }
} }
/* label */ /* label */
label_val = json_tok_escaped_string(cmd, buffer, label); label_val = json_tok_label(cmd, buffer, label);
if (!label_val) { if (!label_val) {
command_fail(cmd, "label '%.*s' not a string", command_fail(cmd, "label '%.*s' not a string or number",
label->end - label->start, buffer + label->start); label->end - label->start, buffer + label->start);
return; return;
} }
@ -306,9 +329,9 @@ static void json_listinvoice_internal(struct command *cmd,
} }
if (labeltok) { if (labeltok) {
label = json_tok_escaped_string(cmd, buffer, labeltok); label = json_tok_label(cmd, buffer, labeltok);
if (!label) { if (!label) {
command_fail(cmd, "label '%.*s' is not a string", command_fail(cmd, "label '%.*s' is not a string or number",
labeltok->end - labeltok->start, labeltok->end - labeltok->start,
buffer + labeltok->start); buffer + labeltok->start);
return; return;
@ -374,9 +397,9 @@ static void json_delinvoice(struct command *cmd,
return; return;
} }
label = json_tok_escaped_string(cmd, buffer, labeltok); label = json_tok_label(cmd, buffer, labeltok);
if (!label) { if (!label) {
command_fail(cmd, "label '%.*s' not a string", command_fail(cmd, "label '%.*s' is not a string or number",
labeltok->end - labeltok->start, labeltok->end - labeltok->start,
buffer + labeltok->start); buffer + labeltok->start);
return; return;
@ -567,9 +590,9 @@ static void json_waitinvoice(struct command *cmd,
} }
/* Search for invoice */ /* Search for invoice */
label = json_tok_escaped_string(cmd, buffer, labeltok); label = json_tok_label(cmd, buffer, labeltok);
if (!label) { if (!label) {
command_fail(cmd, "label '%.*s' is not a string", command_fail(cmd, "label '%.*s' is not a string or number",
labeltok->end - labeltok->start, labeltok->end - labeltok->start,
buffer + labeltok->start); buffer + labeltok->start);
return; return;

23
tests/test_lightningd.py

@ -475,6 +475,29 @@ class LightningDTests(BaseLightningDTests):
b11 = l1.rpc.decodepay(inv['bolt11']) b11 = l1.rpc.decodepay(inv['bolt11'])
assert b11['description'] == weird_desc assert b11['description'] == weird_desc
# Can delete by weird label.
l1.rpc.delinvoice(weird_label, "unpaid")
# We can also use numbers as labels.
weird_label = 25
weird_desc = '"'
l1.rpc.invoice(123000, weird_label, weird_desc)
# FIXME: invoice RPC should return label!
# Can find by this label.
inv = l1.rpc.listinvoices(weird_label)['invoices'][0]
assert inv['label'] == str(weird_label)
# Can find this in list.
inv = l1.rpc.listinvoices()['invoices'][0]
assert inv['label'] == str(weird_label)
b11 = l1.rpc.decodepay(inv['bolt11'])
assert b11['description'] == weird_desc
# Can delete by weird label.
l1.rpc.delinvoice(weird_label, "unpaid")
def test_invoice_expiry(self): def test_invoice_expiry(self):
l1, l2 = self.connect() l1, l2 = self.connect()

Loading…
Cancel
Save