Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jsonrpc: Add description_hash parameter to invoice #4892

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions contrib/pyln-client/pyln/client/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,13 @@ def help(self, command=None):
}
return self.call("help", payload)

def invoice(self, msatoshi, label, description, expiry=None, fallbacks=None, preimage=None, exposeprivatechannels=None, cltv=None):
def invoice(self, msatoshi, label, description, expiry=None, fallbacks=None, preimage=None, exposeprivatechannels=None, cltv=None, description_hash=None):
"""
Create an invoice for {msatoshi} with {label} and {description} with
optional {expiry} seconds (default 1 week).
optional {expiry} seconds (default 1 week), optional {fallbacks}
address list(default empty list) and optional {preimage} (default
autogenerated) and optional {description_hash} (if description
is empty).
"""
payload = {
"msatoshi": msatoshi,
Expand All @@ -855,6 +858,7 @@ def invoice(self, msatoshi, label, description, expiry=None, fallbacks=None, pre
"preimage": preimage,
"exposeprivatechannels": exposeprivatechannels,
"cltv": cltv,
"description_hash": description_hash,
}
return self.call("invoice", payload)

Expand Down
5 changes: 5 additions & 0 deletions doc/lightning-invoice.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SYNOPSIS

**invoice** *msatoshi* *label* *description* \[*expiry*\]
\[*fallbacks*\] \[*preimage*\] \[*exposeprivatechannels*\] \[*cltv*\]
\[*description\_hash*\]

DESCRIPTION
-----------
Expand Down Expand Up @@ -68,6 +69,10 @@ payment.
If specified, *cltv* sets the *min_final_cltv_expiry* for the invoice.
Otherwise, it's set to the parameter **cltv-final**.

A *description\_hash* can be specified when *description* is the empty string,
it specifies a SHA-256 hash of the description to commit to, in hexadecimal format.
This can be used when the invoice protocol communicates the description out of band.

RETURN VALUE
------------

Expand Down
18 changes: 15 additions & 3 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ static struct command_result *json_invoice(struct command *cmd,
#if DEVELOPER
const jsmntok_t *routes;
#endif
struct sha256 *description_hash;

info = tal(cmd, struct invoice_info);
info->cmd = cmd;
Expand All @@ -1151,6 +1152,7 @@ static struct command_result *json_invoice(struct command *cmd,
&info->chanhints),
p_opt_def("cltv", param_number, &cltv,
cmd->ld->config.cltv_final),
p_opt("description_hash", param_sha256, &description_hash),
#if DEVELOPER
p_opt("dev-routes", param_array, &routes),
#endif
Expand Down Expand Up @@ -1204,8 +1206,17 @@ static struct command_result *json_invoice(struct command *cmd,
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;
if (description_hash) {
if (strlen(desc_val) != 0) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Description must be empty if description_hash is set");
}
info->b11->description = NULL;
info->b11->description_hash = tal_steal(info->b11, description_hash);
} else {
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,
Expand Down Expand Up @@ -1245,7 +1256,8 @@ static const struct json_command invoice_command = {
"and {description} with optional {expiry} seconds "
"(default 1 week), optional {fallbacks} address list"
"(default empty list) and optional {preimage} "
"(default autogenerated)"};
"(default autogenerated) and optional "
"{description_hash} (if description is empty)"};
AUTODATA(json_command, &invoice_command);

static void json_add_invoices(struct json_stream *response,
Expand Down
10 changes: 10 additions & 0 deletions tests/test_invoices.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ def test_invoice(node_factory, chainparams):
b11 = l1.rpc.decodepay(inv['bolt11'])
assert b11['min_final_cltv_expiry'] == 99

# Test description_hash option.
h = '5' * 64
inv = l1.rpc.invoice(123000, 'label4', '', '3700', description_hash=h)
b11 = l1.rpc.decodepay(inv['bolt11'])
assert('description' not in b11)
assert(b11['description_hash'] == h)

with pytest.raises(RpcError, match=r"Description must be empty if description_hash is set"):
inv = l1.rpc.invoice(123000, 'label5', 'fail', '3700', description_hash=h)


def test_invoice_zeroval(node_factory):
"""A zero value invoice is unpayable, did you mean 'any'?"""
Expand Down