diff --git a/contrib/pylightning/lightning/lightning.py b/contrib/pylightning/lightning/lightning.py index 2e89d3f0a..f8d87b7ed 100644 --- a/contrib/pylightning/lightning/lightning.py +++ b/contrib/pylightning/lightning/lightning.py @@ -150,7 +150,7 @@ class LightningRpc(UnixDomainSocketRpc): } return self.call("listchannels", payload) - def invoice(self, msatoshi, label, description, expiry=None, fallbacks=None): + def invoice(self, msatoshi, label, description, expiry=None, fallbacks=None, preimage=None): """ Create an invoice for {msatoshi} with {label} and {description} with optional {expiry} seconds (default 1 hour) @@ -160,7 +160,8 @@ class LightningRpc(UnixDomainSocketRpc): "label": label, "description": description, "expiry": expiry, - "fallbacks": fallbacks + "fallbacks": fallbacks, + "preimage": preimage } return self.call("invoice", payload) diff --git a/doc/lightning-invoice.7 b/doc/lightning-invoice.7 index 859b1bc58..7979f64e2 100644 --- a/doc/lightning-invoice.7 +++ b/doc/lightning-invoice.7 @@ -2,12 +2,12 @@ .\" Title: lightning-invoice .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/06/2018 +.\" Date: 04/23/2018 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "LIGHTNING\-INVOICE" "7" "04/06/2018" "\ \&" "\ \&" +.TH "LIGHTNING\-INVOICE" "7" "04/23/2018" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -31,7 +31,7 @@ lightning-invoice \- Protocol for accepting payments\&. .SH "SYNOPSIS" .sp -\fBinvoice\fR \fImsatoshi\fR \fIlabel\fR \fIdescription\fR [\fIexpiry\fR] [\fIfallbacks\fR] +\fBinvoice\fR \fImsatoshi\fR \fIlabel\fR \fIdescription\fR [\fIexpiry\fR] [\fIfallbacks\fR] [\fIpreimage\fR] .SH "DESCRIPTION" .sp The \fBinvoice\fR RPC command creates the expectation of a payment of a given amount of milli\-satoshi: it returns a unique token which another lightning daemon can use to pay this invoice\&. @@ -45,6 +45,8 @@ The \fIdescription\fR is a short description of purpose of payment, e\&.g\&. \fI 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\&. .sp The \fIfallbacks\fR array is one or more fallback addresses to include in the invoice (in order from most\-preferred to least): note that these arrays are not currently tracked to fulfill the invoice\&. +.sp +The \fIpreimage\fR is a 64\-digit hex string to be used as payment preimage for the created invoice\&. By default, if unspecified, lightningd will generate a secure pseudorandom preimage seeded from an appropriate entropy source on your system\&. \fBIMPORTANT\fR: if you specify the \fIpreimage\fR, you are responsible, to ensure appropriate care for generating using a secure pseudorandom generator seeded with sufficient entropy, and keeping the preimage secret\&. This parameter is an advanced feature intended for use with cutting\-edge cryptographic protocols and should not be used unless explicitly needed\&. .SH "RETURN VALUE" .sp On success, a hash is returned as \fIpayment_hash\fR to be given to the payer, and the \fIexpiry_time\fR as a UNIX timestamp\&. It also returns a BOLT11 invoice as \fIbolt11\fR to be given to the payer\&. On failure, an error is returned and no invoice is created\&. If the lightning process fails before responding, the caller should use lightning\-listinvoice(7) to query whether this invoice was created or not\&. diff --git a/doc/lightning-invoice.7.txt b/doc/lightning-invoice.7.txt index 1f21859d5..e64e540ab 100644 --- a/doc/lightning-invoice.7.txt +++ b/doc/lightning-invoice.7.txt @@ -8,7 +8,7 @@ lightning-invoice - Protocol for accepting payments. SYNOPSIS -------- -*invoice* 'msatoshi' 'label' 'description' ['expiry'] ['fallbacks'] +*invoice* 'msatoshi' 'label' 'description' ['expiry'] ['fallbacks'] ['preimage'] DESCRIPTION ----------- @@ -36,6 +36,18 @@ The 'fallbacks' array is one or more fallback addresses to include in the invoice (in order from most-preferred to least): note that these arrays are not currently tracked to fulfill the invoice. +The 'preimage' is a 64-digit hex string to be used as payment preimage +for the created invoice. +By default, if unspecified, lightningd will generate a secure +pseudorandom preimage seeded from an appropriate entropy source on +your system. +*IMPORTANT*: if you specify the 'preimage', you are responsible, to +ensure appropriate care for generating using a secure pseudorandom +generator seeded with sufficient entropy, and keeping the preimage +secret. +This parameter is an advanced feature intended for use with cutting-edge +cryptographic protocols and should not be used unless explicitly needed. + RETURN VALUE ------------ diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 5f0e33bca..d3301ce68 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -156,6 +156,7 @@ static void json_invoice(struct command *cmd, struct invoice invoice; struct invoice_details details; jsmntok_t *msatoshi, *label, *desctok, *exp, *fallback, *fallbacks; + jsmntok_t *preimagetok; u64 *msatoshi_val; const struct json_escaped *label_val, *desc; const char *desc_val; @@ -174,6 +175,7 @@ static void json_invoice(struct command *cmd, "?expiry", &exp, "?fallback", &fallback, "?fallbacks", &fallbacks, + "?preimage", &preimagetok, NULL)) { return; } @@ -281,8 +283,18 @@ static void json_invoice(struct command *cmd, struct preimage r; struct sha256 rhash; - /* Generate random secret preimage and hash. */ - randombytes_buf(r.r, sizeof(r.r)); + if (preimagetok) { + /* Get secret preimage from user. */ + if (!hex_decode(buffer + preimagetok->start, + preimagetok->end - preimagetok->start, + r.r, sizeof(r.r))) { + command_fail(cmd, "preimage must be 64 hex digits"); + return; + } + } else + /* Generate random secret preimage. */ + randombytes_buf(r.r, sizeof(r.r)); + /* Generate preimage hash. */ sha256(&rhash, r.r, sizeof(r.r)); /* Construct bolt11 string. */ diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index cb4c82eb5..c6899dea2 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -445,6 +445,23 @@ class LightningDTests(BaseLightningDTests): assert len(l1.rpc.listinvoices('inv1')['invoices']) == 0 assert len(l1.rpc.listinvoices('inv2')['invoices']) == 0 + def test_invoice_preimage(self): + """Test explicit invoice 'preimage'. + """ + l1, l2 = self.connect() + self.fund_channel(l1, l2, 10**6) + + # I promise the below number is randomly generated + invoice_preimage = "17b08f669513b7379728fc1abcea5eaf3448bc1eba55a68ca2cd1843409cdc04" + + # Make invoice and pay it + inv = l2.rpc.invoice(msatoshi=123456, label="inv", description="?", preimage=invoice_preimage) + payment = l1.rpc.pay(inv['bolt11']) + + # Check preimage was given. + payment_preimage = payment['payment_preimage'] + assert invoice_preimage == payment_preimage + def test_invoice(self): l1 = self.node_factory.get_node() l2 = self.node_factory.get_node()