From 7769903f1abf7dd7c6a89bb9f154f1710f96bcb9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 21 Jul 2021 11:01:39 +0930 Subject: [PATCH] bolt12: import latest spec (timestamp -> created_at). @shesek points out that we called this field created_at in bolt11 decode, which makes more sense anyway. Changelog-EXPERIMENTAL: bolt12 decode `timestamp` field deprecated in favor of new name `created_at`. Signed-off-by: Rusty Russell --- common/bolt12.h | 4 ++-- devtools/bolt12-cli.c | 22 +++++++++++----------- doc/lightning-decode.7 | 8 ++++---- doc/lightning-decode.7.md | 8 ++++---- doc/schemas/decode.schema.json | 14 +++++++++----- plugins/fetchinvoice.c | 14 +++++++------- plugins/offers.c | 17 ++++++++++------- plugins/offers_invreq_hook.c | 22 +++++++++++----------- plugins/pay.c | 14 +++++++------- wire/bolt12_exp_wire.csv | 6 +++--- wire/bolt12_wire.csv | 6 +++--- wire/bolt12_wiregen.c | 18 +++++++++--------- wire/bolt12_wiregen.h | 4 ++-- 13 files changed, 82 insertions(+), 75 deletions(-) diff --git a/common/bolt12.h b/common/bolt12.h index a136e1730..71d17ce89 100644 --- a/common/bolt12.h +++ b/common/bolt12.h @@ -12,10 +12,10 @@ struct feature_set; /* BOLT-offers #12: * - if `relative_expiry` is present: * - MUST reject the invoice if the current time since 1970-01-01 UTC - * is greater than `timestamp` plus `seconds_from_timestamp`. + * is greater than `created_at` plus `seconds_from_creation`. * - otherwise: * - MUST reject the invoice if the current time since 1970-01-01 UTC - * is greater than `timestamp` plus 7200. + * is greater than `created_at` plus 7200. */ #define BOLT12_DEFAULT_REL_EXPIRY 7200 diff --git a/devtools/bolt12-cli.c b/devtools/bolt12-cli.c index 243c09191..4f454eff5 100644 --- a/devtools/bolt12-cli.c +++ b/devtools/bolt12-cli.c @@ -379,9 +379,9 @@ static void print_payer_note(const char *payer_note) (int)tal_bytelen(payer_note), payer_note); } -static void print_timestamp(u64 timestamp) +static void print_created_at(u64 timestamp) { - printf("timestamp: %"PRIu64" (%s)\n", + printf("created_at: %"PRIu64" (%s)\n", timestamp, fmt_time(tmpctx, timestamp)); } @@ -396,27 +396,27 @@ static void print_cltv(u32 cltv) printf("min_final_cltv_expiry: %u\n", cltv); } -static void print_relative_expiry(u64 *timestamp, u32 *relative) +static void print_relative_expiry(u64 *created_at, u32 *relative) { /* Ignore if already malformed */ - if (!timestamp) + if (!created_at) return; /* BOLT-offers #12: * - if `relative_expiry` is present: * - MUST reject the invoice if the current time since 1970-01-01 UTC - * is greater than `timestamp` plus `seconds_from_timestamp`. + * is greater than `created_at` plus `seconds_from_creation`. * - otherwise: * - MUST reject the invoice if the current time since 1970-01-01 UTC - * is greater than `timestamp` plus 7200. + * is greater than `created_at` plus 7200. */ if (!relative) printf("relative_expiry: %u (%s) (default)\n", BOLT12_DEFAULT_REL_EXPIRY, - fmt_time(tmpctx, *timestamp + BOLT12_DEFAULT_REL_EXPIRY)); + fmt_time(tmpctx, *created_at + BOLT12_DEFAULT_REL_EXPIRY)); else printf("relative_expiry: %u (%s)\n", *relative, - fmt_time(tmpctx, *timestamp + *relative)); + fmt_time(tmpctx, *created_at + *relative)); } static void print_fallbacks(const struct tlv_invoice_fallbacks *fallbacks) @@ -622,11 +622,11 @@ int main(int argc, char *argv[]) } if (must_have(invoice, payer_key)) print_payer_key(invoice->payer_key, invoice->payer_info); - if (must_have(invoice, timestamp)) - print_timestamp(*invoice->timestamp); + if (must_have(invoice, created_at)) + print_created_at(*invoice->created_at); if (invoice->payer_note) print_payer_note(invoice->payer_note); - print_relative_expiry(invoice->timestamp, + print_relative_expiry(invoice->created_at, invoice->relative_expiry); if (must_have(invoice, payment_hash)) print_payment_hash(invoice->payment_hash); diff --git a/doc/lightning-decode.7 b/doc/lightning-decode.7 index f4cc5e031..174c04b98 100644 --- a/doc/lightning-decode.7 +++ b/doc/lightning-decode.7 @@ -153,11 +153,11 @@ If \fBtype\fR is "bolt12 invoice", and \fBvalid\fR is \fItrue\fR: .IP \[bu] \fBdescription\fR (string): the description of the purpose of the offer .IP \[bu] -\fBtimestamp\fR (u64): the UNIX timestamp of the invoice +\fBcreated_at\fR (u64): the UNIX timestamp of invoice creation .IP \[bu] \fBpayment_hash\fR (hex): the hash of the \fIpayment_preimage\fR (always 64 characters) .IP \[bu] -\fBrelative_expiry\fR (u32): the number of seconds after \fItimestamp\fR when this expires +\fBrelative_expiry\fR (u32): the number of seconds after \fIcreated_at\fR when this expires .IP \[bu] \fBmin_final_cltv_expiry\fR (u32): the number of blocks required by destination .IP \[bu] @@ -256,7 +256,7 @@ the following warnings are possible: .IP \[bu] \fBwarning_invoice_missing_recurrence_basetime\fR: Has \fBrecurrence_counter\fR without \fBrecurrence_basetime\fR .IP \[bu] -\fBwarning_invoice_missing_timestamp\fR: Missing \fBtimestamp\fR +\fBwarning_invoice_missing_created_at\fR: Missing \fBcreated_at\fR .IP \[bu] \fBwarning_invoice_missing_payment_hash\fR: Missing \fBpayment_hash\fR .IP \[bu] @@ -414,4 +414,4 @@ Rusty Russell \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:cd54af7c631f06b3db72848cdf90951ceb14d89b8bca981dba69244cd2ddbae5 +\" SHA256STAMP:dda6e1cff3e58c38b637c5a11673b5a9f4837cbdf89ed3be52a8bfc874af87d4 diff --git a/doc/lightning-decode.7.md b/doc/lightning-decode.7.md index e0b62d39b..81e6f24a6 100644 --- a/doc/lightning-decode.7.md +++ b/doc/lightning-decode.7.md @@ -70,9 +70,9 @@ If **type** is "bolt12 invoice", and **valid** is *true*: - **signature** (bip340sig): BIP-340 signature of the *node_id* on this offer - **amount_msat** (msat): the amount in bitcoin - **description** (string): the description of the purpose of the offer - - **timestamp** (u64): the UNIX timestamp of the invoice + - **created_at** (u64): the UNIX timestamp of invoice creation - **payment_hash** (hex): the hash of the *payment_preimage* (always 64 characters) - - **relative_expiry** (u32): the number of seconds after *timestamp* when this expires + - **relative_expiry** (u32): the number of seconds after *created_at* when this expires - **min_final_cltv_expiry** (u32): the number of blocks required by destination - **offer_id** (hex, optional): the id of this offer (merkle hash of non-signature fields) (always 64 characters) - **chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only): @@ -108,7 +108,7 @@ If **type** is "bolt12 invoice", and **valid** is *false*: - **warning_invoice_missing_blinded_payinfo**: Has **paths** without payinfo - **warning_invoice_invalid_blinded_payinfo**: Does not have exactly one payinfo for each of **paths** - **warning_invoice_missing_recurrence_basetime**: Has **recurrence_counter** without **recurrence_basetime** - - **warning_invoice_missing_timestamp**: Missing **timestamp** + - **warning_invoice_missing_created_at**: Missing **created_at** - **warning_invoice_missing_payment_hash**: Missing **payment_hash** - **warning_invoice_refund_signature_missing_payer_key**: Missing **payer_key** for refund_signature - **warning_invoice_refund_signature_invalid**: **refund_signature** incorrect @@ -183,4 +183,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:8ca0b9178b8ea6575cd80291001263dc27f721664648086a7c1a02efcb545ee7) +[comment]: # ( SHA256STAMP:fbbfc116c23489d4f346b4d5eb06dd922592c543ec68e5a76b6822b2658bd46d) diff --git a/doc/schemas/decode.schema.json b/doc/schemas/decode.schema.json index ad168d24e..33890f511 100644 --- a/doc/schemas/decode.schema.json +++ b/doc/schemas/decode.schema.json @@ -263,7 +263,7 @@ } }, "then": { - "required": [ "node_id", "signature", "amount_msat", "description", "timestamp", "payment_hash", "relative_expiry", "min_final_cltv_expiry" ], + "required": [ "node_id", "signature", "amount_msat", "description", "created_at", "payment_hash", "relative_expiry", "min_final_cltv_expiry" ], "additionalProperties": false, "properties": { "type": { }, @@ -378,8 +378,11 @@ "description": "the payer-provided blob to derive payer_key" }, "timestamp": { + "deprecated": true + }, + "created_at": { "type": "u64", - "description": "the UNIX timestamp of the invoice" + "description": "the UNIX timestamp of invoice creation" }, "payment_hash": { "type": "hex", @@ -389,7 +392,7 @@ }, "relative_expiry": { "type": "u32", - "description": "the number of seconds after *timestamp* when this expires" + "description": "the number of seconds after *created_at* when this expires" }, "min_final_cltv_expiry": { "type": "u32", @@ -462,6 +465,7 @@ "payer_key": { }, "payer_info": { }, "timestamp": { }, + "created_at": { }, "payment_hash": { }, "relative_expiry": { }, "min_final_cltv_expiry": { }, @@ -487,9 +491,9 @@ "type": "string", "description": "Has **recurrence_counter** without **recurrence_basetime**" }, - "warning_invoice_missing_timestamp": { + "warning_invoice_missing_created_at": { "type": "string", - "description": "Missing **timestamp**" + "description": "Missing **created_at**" }, "warning_invoice_missing_payment_hash": { "type": "string", diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 12a080081..8882a8f0a 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -1413,17 +1413,17 @@ static struct command_result *json_sendinvoice(struct command *cmd, } /* BOLT-offers #12: - * - MUST set `timestamp` to the number of seconds since Midnight 1 - * January 1970, UTC. + * - MUST set `created_at` to the number of seconds since Midnight 1 + * January 1970, UTC when the offer was created. */ - sent->inv->timestamp = tal(sent->inv, u64); - *sent->inv->timestamp = time_now().ts.tv_sec; + sent->inv->created_at = tal(sent->inv, u64); + *sent->inv->created_at = time_now().ts.tv_sec; /* BOLT-offers #12: * - if the expiry for accepting payment is not 7200 seconds after - * `timestamp`: - * - MUST set `relative_expiry` `seconds_from_timestamp` to the number - * of seconds after `timestamp` that payment of this invoice should + * `created_at`: + * - MUST set `relative_expiry` `seconds_from_creation` to the number + * of seconds after `created_at` that payment of this invoice should * not be attempted. */ if (sent->wait_timeout != 7200) { diff --git a/plugins/offers.c b/plugins/offers.c index dad431d97..305ec1655 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -543,13 +543,16 @@ static void json_add_b12_invoice(struct json_stream *js, tal_bytelen(invoice->payer_note)); /* BOLT-offers #12: - * - MUST reject the invoice if `timestamp` is not present. + * - MUST reject the invoice if `created_at` is not present. */ - if (invoice->timestamp) - json_add_u64(js, "timestamp", *invoice->timestamp); - else { - json_add_string(js, "warning_invoice_missing_timestamp", - "invoices without a timestamp are invalid"); + if (invoice->created_at) { + /* FIXME: Remove soon! */ + if (deprecated_apis) + json_add_u64(js, "timestamp", *invoice->created_at); + json_add_u64(js, "created_at", *invoice->created_at); + } else { + json_add_string(js, "warning_invoice_missing_created_at", + "invoices without created_at are invalid"); valid = false; } @@ -567,7 +570,7 @@ static void json_add_b12_invoice(struct json_stream *js, /* BOLT-offers #12: * * - if the expiry for accepting payment is not 7200 seconds after - * `timestamp`: + * `created_at`: * - MUST set `relative_expiry` */ if (invoice->relative_expiry) diff --git a/plugins/offers_invreq_hook.c b/plugins/offers_invreq_hook.c index 843738cad..2facf35ee 100644 --- a/plugins/offers_invreq_hook.c +++ b/plugins/offers_invreq_hook.c @@ -114,8 +114,8 @@ test_field(struct command *cmd, * - if the invoice corresponds to an offer with `recurrence`: * ... * - if it sets `relative_expiry`: - * - MUST NOT set `relative_expiry` `seconds_from_timestamp` more than the - * number of seconds after `timestamp` that payment for this period will + * - MUST NOT set `relative_expiry` `seconds_from_creation` more than the + * number of seconds after `created_at` that payment for this period will * be accepted. */ static void set_recurring_inv_expiry(struct tlv_invoice *inv, u64 last_pay) @@ -123,10 +123,10 @@ static void set_recurring_inv_expiry(struct tlv_invoice *inv, u64 last_pay) inv->relative_expiry = tal(inv, u32); /* Don't give them a 0 second invoice, even if it's true. */ - if (last_pay <= *inv->timestamp) + if (last_pay <= *inv->created_at) *inv->relative_expiry = 1; else - *inv->relative_expiry = last_pay - *inv->timestamp; + *inv->relative_expiry = last_pay - *inv->created_at; /* FIXME: Shorten expiry if we're doing currency conversion! */ } @@ -292,14 +292,14 @@ static struct command_result *check_period(struct command *cmd, ir->offer->recurrence_base, basetime, period_idx, &paywindow_start, &paywindow_end); - if (*ir->inv->timestamp < paywindow_start) { + if (*ir->inv->created_at < paywindow_start) { return fail_invreq(cmd, ir, "period_index %"PRIu64 " too early (start %"PRIu64")", period_idx, paywindow_start); } - if (*ir->inv->timestamp > paywindow_end) { + if (*ir->inv->created_at > paywindow_end) { return fail_invreq(cmd, ir, "period_index %"PRIu64 " too late (ended %"PRIu64")", @@ -327,9 +327,9 @@ static struct command_result *check_period(struct command *cmd, u64 end = offer_period_start(basetime, period_idx + 1, ir->offer->recurrence); - if (*ir->inv->timestamp > start) { + if (*ir->inv->created_at > start) { *ir->inv->amount - *= (double)((*ir->inv->timestamp - start) + *= (double)((*ir->inv->created_at - start) / (end - start)); /* Round up to make it non-zero if necessary. */ if (*ir->inv->amount == 0) @@ -401,7 +401,7 @@ static struct command_result *check_previous_invoice(struct command *cmd, /* No previous? Just pass through */ if (*ir->invreq->recurrence_counter == 0) - return check_period(cmd, ir, *ir->inv->timestamp); + return check_period(cmd, ir, *ir->inv->created_at); req = jsonrpc_request_start(cmd->plugin, cmd, "listinvoices", @@ -806,8 +806,8 @@ static struct command_result *listoffers_done(struct command *cmd, ir->inv->cltv = tal_dup(ir->inv, u32, &cltv_final); - ir->inv->timestamp = tal(ir->inv, u64); - *ir->inv->timestamp = time_now().ts.tv_sec; + ir->inv->created_at = tal(ir->inv, u64); + *ir->inv->created_at = time_now().ts.tv_sec; /* We may require currency lookup; if so, do it now. */ if (ir->offer->amount && ir->offer->currency) diff --git a/plugins/pay.c b/plugins/pay.c index 95d09ba84..5925354ae 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -2072,9 +2072,9 @@ static struct command_result *json_paymod(struct command *cmd, if (!b12->payment_hash) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "invoice missing payment_hash"); - if (!b12->timestamp) + if (!b12->created_at) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, - "invoice missing timestamp"); + "invoice missing created_at"); if (b12->amount) { invmsat = tal(cmd, struct amount_msat); *invmsat = amount_msat(*b12->amount); @@ -2110,17 +2110,17 @@ static struct command_result *json_paymod(struct command *cmd, /* BOLT-offers #12: * - if `relative_expiry` is present: * - MUST reject the invoice if the current time since - * 1970-01-01 UTC is greater than `timestamp` plus - * `seconds_from_timestamp`. + * 1970-01-01 UTC is greater than `created_at` plus + * `seconds_from_creation`. * - otherwise: * - MUST reject the invoice if the current time since - * 1970-01-01 UTC is greater than `timestamp` plus + * 1970-01-01 UTC is greater than `created_at` plus * 7200. */ if (b12->relative_expiry) - invexpiry = *b12->timestamp + *b12->relative_expiry; + invexpiry = *b12->created_at + *b12->relative_expiry; else - invexpiry = *b12->timestamp + BOLT12_DEFAULT_REL_EXPIRY; + invexpiry = *b12->created_at + BOLT12_DEFAULT_REL_EXPIRY; p->local_offer_id = tal_steal(p, local_offer_id); } diff --git a/wire/bolt12_exp_wire.csv b/wire/bolt12_exp_wire.csv index 727dcfbfa..4eb795220 100644 --- a/wire/bolt12_exp_wire.csv +++ b/wire/bolt12_exp_wire.csv @@ -102,12 +102,12 @@ tlvtype,invoice,payer_note,39 tlvdata,invoice,payer_note,note,utf8,... tlvtype,invoice,payer_info,50 tlvdata,invoice,payer_info,blob,byte,... -tlvtype,invoice,timestamp,40 -tlvdata,invoice,timestamp,timestamp,tu64, +tlvtype,invoice,created_at,40 +tlvdata,invoice,created_at,timestamp,tu64, tlvtype,invoice,payment_hash,42 tlvdata,invoice,payment_hash,payment_hash,sha256, tlvtype,invoice,relative_expiry,44 -tlvdata,invoice,relative_expiry,seconds_from_timestamp,tu32, +tlvdata,invoice,relative_expiry,seconds_from_creation,tu32, tlvtype,invoice,cltv,46 tlvdata,invoice,cltv,min_final_cltv_expiry,tu32, tlvtype,invoice,fallbacks,48 diff --git a/wire/bolt12_wire.csv b/wire/bolt12_wire.csv index 727dcfbfa..4eb795220 100644 --- a/wire/bolt12_wire.csv +++ b/wire/bolt12_wire.csv @@ -102,12 +102,12 @@ tlvtype,invoice,payer_note,39 tlvdata,invoice,payer_note,note,utf8,... tlvtype,invoice,payer_info,50 tlvdata,invoice,payer_info,blob,byte,... -tlvtype,invoice,timestamp,40 -tlvdata,invoice,timestamp,timestamp,tu64, +tlvtype,invoice,created_at,40 +tlvdata,invoice,created_at,timestamp,tu64, tlvtype,invoice,payment_hash,42 tlvdata,invoice,payment_hash,payment_hash,sha256, tlvtype,invoice,relative_expiry,44 -tlvdata,invoice,relative_expiry,seconds_from_timestamp,tu32, +tlvdata,invoice,relative_expiry,seconds_from_creation,tu32, tlvtype,invoice,cltv,46 tlvdata,invoice,cltv,min_final_cltv_expiry,tu32, tlvtype,invoice,fallbacks,48 diff --git a/wire/bolt12_wiregen.c b/wire/bolt12_wiregen.c index a5d1792a2..62b683520 100644 --- a/wire/bolt12_wiregen.c +++ b/wire/bolt12_wiregen.c @@ -1342,28 +1342,28 @@ static void fromwire_tlv_invoice_payer_info(const u8 **cursor, size_t *plen, voi r->payer_info = *plen ? tal_arr(r, u8, *plen) : NULL; fromwire_u8_array(cursor, plen, r->payer_info, *plen); } -/* INVOICE MSG: timestamp */ -static u8 *towire_tlv_invoice_timestamp(const tal_t *ctx, const void *vrecord) +/* INVOICE MSG: created_at */ +static u8 *towire_tlv_invoice_created_at(const tal_t *ctx, const void *vrecord) { const struct tlv_invoice *r = vrecord; u8 *ptr; - if (!r->timestamp) + if (!r->created_at) return NULL; ptr = tal_arr(ctx, u8, 0); - towire_tu64(&ptr, *r->timestamp); + towire_tu64(&ptr, *r->created_at); return ptr; } -static void fromwire_tlv_invoice_timestamp(const u8 **cursor, size_t *plen, void *vrecord) +static void fromwire_tlv_invoice_created_at(const u8 **cursor, size_t *plen, void *vrecord) { struct tlv_invoice *r = vrecord; - r->timestamp = tal(r, u64); + r->created_at = tal(r, u64); -*r->timestamp = fromwire_tu64(cursor, plen); +*r->created_at = fromwire_tu64(cursor, plen); } /* INVOICE MSG: payment_hash */ static u8 *towire_tlv_invoice_payment_hash(const tal_t *ctx, const void *vrecord) @@ -1553,7 +1553,7 @@ static const struct tlv_record_type tlvs_invoice[] = { { 36, towire_tlv_invoice_recurrence_counter, fromwire_tlv_invoice_recurrence_counter }, { 38, towire_tlv_invoice_payer_key, fromwire_tlv_invoice_payer_key }, { 39, towire_tlv_invoice_payer_note, fromwire_tlv_invoice_payer_note }, - { 40, towire_tlv_invoice_timestamp, fromwire_tlv_invoice_timestamp }, + { 40, towire_tlv_invoice_created_at, fromwire_tlv_invoice_created_at }, { 42, towire_tlv_invoice_payment_hash, fromwire_tlv_invoice_payment_hash }, { 44, towire_tlv_invoice_relative_expiry, fromwire_tlv_invoice_relative_expiry }, { 46, towire_tlv_invoice_cltv, fromwire_tlv_invoice_cltv }, @@ -1684,4 +1684,4 @@ bool invoice_error_is_valid(const struct tlv_invoice_error *record, size_t *err_ return tlv_fields_valid(record->fields, NULL, err_index); } -// SHA256STAMP:27ffc38bc2be76e159508470734655f35e59d82927beb8c1f62917e592d76d10 +// SHA256STAMP:2946a3a3734bd6af218cb73b4d42ec16fe68c1041b48e084cc160810870bcdd5 diff --git a/wire/bolt12_wiregen.h b/wire/bolt12_wiregen.h index 0f331da8a..527125b7b 100644 --- a/wire/bolt12_wiregen.h +++ b/wire/bolt12_wiregen.h @@ -120,7 +120,7 @@ struct tlv_invoice { struct pubkey32 *payer_key; utf8 *payer_note; u8 *payer_info; - u64 *timestamp; + u64 *created_at; struct sha256 *payment_hash; u32 *relative_expiry; u32 *cltv; @@ -323,4 +323,4 @@ struct fallback_address *fromwire_fallback_address(const tal_t *ctx, const u8 ** #endif /* LIGHTNING_WIRE_BOLT12_WIREGEN_H */ -// SHA256STAMP:27ffc38bc2be76e159508470734655f35e59d82927beb8c1f62917e592d76d10 +// SHA256STAMP:2946a3a3734bd6af218cb73b4d42ec16fe68c1041b48e084cc160810870bcdd5