Skip to content

Commit

Permalink
invoice: allow numeric labels again.
Browse files Browse the repository at this point in the history
Fixes: ElementsProject#1291
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell authored and cdecker committed Mar 29, 2018
1 parent dc25e3a commit a85ead7
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 16 deletions.
8 changes: 4 additions & 4 deletions doc/lightning-invoice.7
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: lightning-invoice
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 01/16/2018
.\" Date: 03/28/2018
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-INVOICE" "7" "01/16/2018" "\ \&" "\ \&"
.TH "LIGHTNING\-INVOICE" "7" "03/28/2018" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
Expand Down Expand Up @@ -38,9 +38,9 @@ The \fBinvoice\fR RPC command creates the expectation of a payment of a given am
.sp
The \fImsatoshi\fR can be the string "any", which creates an invoice that can be paid with any amount\&.
.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
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
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"
Expand Down
7 changes: 4 additions & 3 deletions doc/lightning-invoice.7.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ lightning daemon can use to pay this invoice.
The 'msatoshi' can be the string "any", which creates an invoice
that can be paid with any amount.

The 'label' must be a unique string; it is never revealed to other nodes on
the lightning network, but it can be used to query the status of this
invoice.
The 'label' 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.

The 'description' is a short description of purpose of payment,
e.g. '1 cup of coffee'. This value is encoded into the BOLT11 invoice
Expand Down
2 changes: 1 addition & 1 deletion external/libwally-core
39 changes: 31 additions & 8 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,29 @@ static bool hsm_sign_b11(const u5 *u5bytes,
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,
const char *buffer, const jsmntok_t *params)
{
Expand Down Expand Up @@ -148,9 +171,9 @@ static void json_invoice(struct command *cmd,
}
}
/* label */
label_val = json_tok_escaped_string(cmd, buffer, label);
label_val = json_tok_label(cmd, buffer, label);
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);
return;
}
Expand Down Expand Up @@ -306,9 +329,9 @@ static void json_listinvoice_internal(struct command *cmd,
}

if (labeltok) {
label = json_tok_escaped_string(cmd, buffer, labeltok);
label = json_tok_label(cmd, buffer, labeltok);
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,
buffer + labeltok->start);
return;
Expand Down Expand Up @@ -374,9 +397,9 @@ static void json_delinvoice(struct command *cmd,
return;
}

label = json_tok_escaped_string(cmd, buffer, labeltok);
label = json_tok_label(cmd, buffer, labeltok);
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,
buffer + labeltok->start);
return;
Expand Down Expand Up @@ -567,9 +590,9 @@ static void json_waitinvoice(struct command *cmd,
}

/* Search for invoice */
label = json_tok_escaped_string(cmd, buffer, labeltok);
label = json_tok_label(cmd, buffer, labeltok);
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,
buffer + labeltok->start);
return;
Expand Down
23 changes: 23 additions & 0 deletions tests/test_lightningd.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,29 @@ def test_invoice_weirdstring(self):
b11 = l1.rpc.decodepay(inv['bolt11'])
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):
l1, l2 = self.connect()

Expand Down

0 comments on commit a85ead7

Please sign in to comment.