invoices: display the payer note if it's for local offer, allow in fetchinvoice.

We don't do it for sendinvoice (yet?).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-EXPERIMENTAL: `fetchinvoice` can take a payer note, and `listinvoice` will show the payer_notes received.
This commit is contained in:
Rusty Russell 2021-07-02 09:41:35 +09:30
parent 12dd3a439b
commit 2cb16a65c4
12 changed files with 59 additions and 9 deletions

View file

@ -60,6 +60,8 @@ On success, an object is returned, containing:
\fBpayment_preimage\fR (hex, optional): the proof of payment: SHA256 of this \fBpayment_hash\fR (always 64 characters)
.IP \[bu]
\fBlocal_offer_id\fR (hex, optional): the \fIid\fR of our offer which created this invoice (\fBexperimental-offers\fR only)\. (always 64 characters)
.IP \[bu]
\fBpayer_note\fR (string, optional): the optional \fIpayer_note\fR from invoice_request which created this invoice (\fBexperimental-offers\fR only)\.
.RE
@ -91,4 +93,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:fd9275c58b67eca68aafee27cb79a558669b12b8cda56872f1db798637006278
\" SHA256STAMP:98d930c694694138e37f3db934e2e8d5f4454c6761da5dfae667dd9b869d972c

View file

@ -45,6 +45,7 @@ On success, an object is returned, containing:
- **paid_at** (u64, optional): UNIX timestamp of when invoice was paid (**status** *paid* only)
- **payment_preimage** (hex, optional): the proof of payment: SHA256 of this **payment_hash** (always 64 characters)
- **local_offer_id** (hex, optional): the *id* of our offer which created this invoice (**experimental-offers** only). (always 64 characters)
- **payer_note** (string, optional): the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only).
[comment]: # (GENERATE-FROM-SCHEMA-END)
On failure, an error is returned and no invoice is created. If the
@ -72,4 +73,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:948d344d5f589050127bd5181689882c6fad036799fa6ff039a83194ff5fd098)
[comment]: # ( SHA256STAMP:72b3b200462e9e16c72dd5e3281d35d9ec2eded62e6a7d87e9361573c85dcc32)

View file

@ -46,6 +46,8 @@ If \fBbolt12\fR is present:
.RS
.IP \[bu]
\fBlocal_offer_id\fR (hex, optional): offer for which this invoice was created
.IP \[bu]
\fBpayer_note\fR (string, optional): the optional \fIpayer_note\fR from invoice_request which created this invoice
.RE
@ -93,4 +95,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:59f9becf74ee1b70ad9eb4316baaed1d26a95e34c3a5000e095fc8b7bfa291cf
\" SHA256STAMP:67e7b489e78df3ad58efad5cad431d5b927a9294b7cbe2ebfef6903fbd2be170

View file

@ -33,6 +33,7 @@ On success, an object is returned, containing:
If **bolt12** is present:
- **local_offer_id** (hex, optional): offer for which this invoice was created
- **payer_note** (string, optional): the optional *payer_note* from invoice_request which created this invoice
If **status** is "paid":
- **pay_index** (u64): unique index for this invoice payment
@ -71,4 +72,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:62a3bdd502ed0b3b555f3cfda6a0e5f7c2417ce0f5b23202d613216de58a23f3)
[comment]: # ( SHA256STAMP:65c14a16b939461a06d81b0ff41e976ea4c7bf963cccdeba47739fe9ca1658a1)

View file

@ -39,6 +39,8 @@ On success, an object containing \fBinvoices\fR is returned\. It is an array of
\fBbolt12\fR (string, optional): the BOLT12 string (always present unless \fIbolt11\fR is)
.IP \[bu]
\fBlocal_offer_id\fR (hex, optional): the \fIid\fR of our offer which created this invoice (\fBexperimental-offers\fR only)\. (always 64 characters)
.IP \[bu]
\fBpayer_note\fR (string, optional): the optional \fIpayer_note\fR from invoice_request which created this invoice (\fBexperimental-offers\fR only)\.
.RE
@ -67,4 +69,4 @@ Rusty Russell \fI<rusty@rustcorp.com.au\fR> is mainly responsible\.
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:d6bc8b6c09aee1f5e29900fffacbc9d3fdf1e32d27e7b90b0709a5f50ecb5c13
\" SHA256STAMP:39640db51e7edd166966ff0f68bc1448328016fa23b56cf2e6e93961e62f458a

View file

@ -31,6 +31,7 @@ On success, an object containing **invoices** is returned. It is an array of ob
- **bolt11** (string, optional): the BOLT11 string (always present unless *bolt12* is)
- **bolt12** (string, optional): the BOLT12 string (always present unless *bolt11* is)
- **local_offer_id** (hex, optional): the *id* of our offer which created this invoice (**experimental-offers** only). (always 64 characters)
- **payer_note** (string, optional): the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only).
If **status** is "paid":
- **pay_index** (u64): Unique incrementing index for this payment
@ -54,4 +55,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:cc6d7b4549d2ab905ab18041f34d13143e4ffed2bb6cc7c1df0307800e59a2fa)
[comment]: # ( SHA256STAMP:99dd5cb3f84e8201903e531b601a04dafde3f6eae3f582b538caea7fac20aad0)

View file

@ -62,6 +62,10 @@
"description": "the *id* of our offer which created this invoice (**experimental-offers** only).",
"maxLength": 64,
"minLength": 64
},
"payer_note": {
"type": "string",
"description": "the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only)."
}
}
}

View file

@ -67,6 +67,10 @@
"local_offer_id": {
"type": "hex",
"description": "offer for which this invoice was created"
},
"payer_note": {
"type": "string",
"description": "the optional *payer_note* from invoice_request which created this invoice"
}
}
},
@ -111,6 +115,7 @@
"amount_msat": { },
"description": { },
"payment_hash": { },
"payer_note": { },
"local_offer_id": { },
"pay_index": {
"type": "u64",
@ -145,6 +150,7 @@
"payment_hash": { },
"expires_at": { },
"pay_index": { },
"payer_note": { },
"local_offer_id": { }
}
}

View file

@ -54,6 +54,10 @@
"description": "the *id* of our offer which created this invoice (**experimental-offers** only).",
"maxLength": 64,
"minLength": 64
},
"payer_note": {
"type": "string",
"description": "the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only)."
}
},
"allOf": [
@ -79,6 +83,7 @@
"bolt11": { },
"bolt12": { },
"local_offer_id": { },
"payer_note": { },
"expires_at": { },
"pay_index": {
"type": "u64",
@ -115,6 +120,7 @@
"bolt11": { },
"bolt12": { },
"local_offer_id": { },
"payer_note": { },
"expires_at": { }
}
}

View file

@ -72,8 +72,22 @@ static void json_add_invoice(struct json_stream *response,
json_add_string(response, "description", inv->description);
json_add_u64(response, "expires_at", inv->expiry_time);
if (inv->local_offer_id)
if (inv->local_offer_id) {
char *fail;
struct tlv_invoice *tinv;
json_add_sha256(response, "local_offer_id", inv->local_offer_id);
/* Everyone loves seeing their own payer notes!
* Well: they will. Trust me. */
tinv = invoice_decode(tmpctx,
inv->invstring, strlen(inv->invstring),
NULL, NULL, &fail);
if (tinv && tinv->payer_note)
json_add_stringn(response, "payer_note",
tinv->payer_note,
tal_bytelen(tinv->payer_note));
}
}
static struct command_result *tell_waiter(struct command *cmd,

View file

@ -830,7 +830,7 @@ static struct command_result *json_fetchinvoice(struct command *cmd,
const jsmntok_t *params)
{
struct amount_msat *msat;
const char *rec_label;
const char *rec_label, *payer_note;
struct out_req *req;
struct tlv_invoice_request *invreq;
struct sent *sent = tal(cmd, struct sent);
@ -847,6 +847,7 @@ static struct command_result *json_fetchinvoice(struct command *cmd,
&invreq->recurrence_start),
p_opt("recurrence_label", param_string, &rec_label),
p_opt_def("timeout", param_number, &timeout, 60),
p_opt("payer_note", param_string, &payer_note),
NULL))
return command_param_failed();
@ -997,6 +998,12 @@ static struct command_result *json_fetchinvoice(struct command *cmd,
invreq->features
= plugin_feature_set(cmd->plugin)->bits[BOLT11_FEATURE];
/* invreq->payer_note is not a nul-terminated string! */
if (payer_note)
invreq->payer_note = tal_dup_arr(invreq, utf8,
payer_note, strlen(payer_note),
0);
/* Make the invoice request (fills in payer_key and payer_info) */
req = jsonrpc_request_start(cmd->plugin, cmd, "createinvoicerequest",
&invreq_done,

View file

@ -3992,7 +3992,8 @@ def test_fetchinvoice(node_factory, bitcoind):
'description': 'simple test'})
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12_unsigned']})
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12_unsigned'],
'payer_note': 'Thanks for the fish!'})
assert inv1 != inv2
assert 'next_period' not in inv1
assert 'next_period' not in inv2
@ -4005,6 +4006,9 @@ def test_fetchinvoice(node_factory, bitcoind):
# listinvoices will show these on l3
assert [x['local_offer_id'] for x in l3.rpc.listinvoices()['invoices']] == [offer1['offer_id'], offer1['offer_id']]
assert 'payer_note' not in only_one(l3.rpc.call('listinvoices', {'invstring': inv1['invoice']})['invoices'])
assert only_one(l3.rpc.call('listinvoices', {'invstring': inv2['invoice']})['invoices'])['payer_note'] == 'Thanks for the fish!'
# We can also set the amount explicitly, to tip.
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'msatoshi': 3})
assert l1.rpc.call('decode', [inv1['invoice']])['amount_msat'] == 3