Skip to content

Commit

Permalink
bolt12: import the latest spec, update to fit.
Browse files Browse the repository at this point in the history
I know this is an unforgivably large diff, but the spec has changed so
much that most of this amounts to a rewrite.

Some points:
* We no longer have "offer_id" fields, we generate that locally, as all
  offer fields are mirrored into invoice_request and then invoice.
* Because of that mirroring, field names all have explicit offer/invreq/invoice
  prefixes.
* The `refund_for` fields have been removed from spec: will re-add locally later.
* quantity_min was removed, max == 0 now mean "must specify a quantity".
* I have put recurrence fields back in locally.

This brings us to 655df03d8729c0918bdacac99eb13fdb0ee93345 ("BOLT 12:
add explicit invoice_node_id.")

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell authored and cdecker committed Nov 9, 2022
1 parent 846a520 commit 1e3cb01
Show file tree
Hide file tree
Showing 21 changed files with 1,377 additions and 1,379 deletions.
54 changes: 21 additions & 33 deletions common/bolt12.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
#include <time.h>

/* If chains is NULL, max_num_chains is ignored */
static bool bolt12_chains_match(const struct bitcoin_blkid *chains,
size_t max_num_chains,
const struct chainparams *must_be_chain)
bool bolt12_chains_match(const struct bitcoin_blkid *chains,
size_t max_num_chains,
const struct chainparams *must_be_chain)
{
/* BOLT-offers #12:
* - if the chain for the invoice is not solely bitcoin:
Expand Down Expand Up @@ -181,26 +181,13 @@ struct tlv_offer *offer_decode(const tal_t *ctx,

*fail = check_features_and_chain(ctx,
our_features, must_be_chain,
offer->features,
offer->offer_features,
BOLT12_OFFER_FEATURE,
offer->chains,
tal_count(offer->chains));
offer->offer_chains,
tal_count(offer->offer_chains));
if (*fail)
return tal_free(offer);

/* BOLT-offers #12:
* - if `signature` is present, but is not a valid signature using
* `node_id` as described in [Signature Calculation](#signature-calculation):
* - MUST NOT respond to the offer.
*/
if (offer->signature) {
*fail = check_signature(ctx, offer->fields,
"offer", "signature",
offer->node_id, offer->signature);
if (*fail)
return tal_free(offer);
}

return offer;
}

Expand Down Expand Up @@ -230,15 +217,15 @@ struct tlv_invoice_request *invrequest_decode(const tal_t *ctx,

invrequest = fromwire_tlv_invoice_request(ctx, &data, &dlen);
if (!invrequest) {
*fail = tal_fmt(ctx, "invalid invoice_request data");
*fail = tal_fmt(ctx, "invalid invreq data");
return NULL;
}

*fail = check_features_and_chain(ctx,
our_features, must_be_chain,
invrequest->features,
invrequest->invreq_features,
BOLT12_INVREQ_FEATURE,
invrequest->chain, 1);
invrequest->invreq_chain, 1);
if (*fail)
return tal_free(invrequest);

Expand Down Expand Up @@ -277,9 +264,9 @@ struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx,

*fail = check_features_and_chain(ctx,
our_features, must_be_chain,
invoice->features,
invoice->invoice_features,
BOLT12_INVOICE_FEATURE,
invoice->chain, 1);
invoice->invreq_chain, 1);
if (*fail)
return tal_free(invoice);

Expand Down Expand Up @@ -328,7 +315,7 @@ static u64 time_change(u64 prevstart, u32 number,
}

u64 offer_period_start(u64 basetime, size_t n,
const struct tlv_offer_recurrence *recur)
const struct recurrence *recur)
{
/* BOLT-offers-recurrence #12:
* 1. A `time_unit` defining 0 (seconds), 1 (days), 2 (months),
Expand All @@ -349,9 +336,9 @@ u64 offer_period_start(u64 basetime, size_t n,
}
}

void offer_period_paywindow(const struct tlv_offer_recurrence *recurrence,
const struct tlv_offer_recurrence_paywindow *recurrence_paywindow,
const struct tlv_offer_recurrence_base *recurrence_base,
void offer_period_paywindow(const struct recurrence *recurrence,
const struct recurrence_paywindow *recurrence_paywindow,
const struct recurrence_base *recurrence_base,
u64 basetime, u64 period_idx,
u64 *start, u64 *end)
{
Expand All @@ -364,9 +351,9 @@ void offer_period_paywindow(const struct tlv_offer_recurrence *recurrence,
/* BOLT-offers-recurrence #12:
* - if the offer has a `recurrence_basetime` or the
* `recurrence_counter` is non-zero:
* - SHOULD NOT send an `invoice_request` for a period prior to
* - SHOULD NOT send an `invreq` for a period prior to
* `seconds_before` seconds before that period start.
* - SHOULD NOT send an `invoice_request` for a period later
* - SHOULD NOT send an `invreq` for a period later
* than `seconds_after` seconds past that period start.
*/
*start = pstart - recurrence_paywindow->seconds_before;
Expand All @@ -381,7 +368,7 @@ void offer_period_paywindow(const struct tlv_offer_recurrence *recurrence,
} else {
/* BOLT-offers-recurrence #12:
* - otherwise:
* - SHOULD NOT send an `invoice_request` with
* - SHOULD NOT send an `invreq` with
* `recurrence_counter` is non-zero for a period whose
* immediate predecessor has not yet begun.
*/
Expand All @@ -392,7 +379,7 @@ void offer_period_paywindow(const struct tlv_offer_recurrence *recurrence,
recurrence);

/* BOLT-offers-recurrence #12:
* - SHOULD NOT send an `invoice_request` for a period which
* - SHOULD NOT send an `invreq` for a period which
* has already passed.
*/
*end = offer_period_start(basetime, period_idx+1,
Expand All @@ -413,7 +400,8 @@ struct tlv_invoice *invoice_decode(const tal_t *ctx,
if (invoice) {
*fail = check_signature(ctx, invoice->fields,
"invoice", "signature",
invoice->node_id, invoice->signature);
invoice->invoice_node_id,
invoice->signature);
if (*fail)
invoice = tal_free(invoice);
}
Expand Down
20 changes: 13 additions & 7 deletions common/bolt12.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ char *invrequest_encode(const tal_t *ctx,
/**
* invrequest_decode - decode this complete bolt12 text into a TLV.
* @ctx: the context to allocate return or *@fail off.
* @b12: the invoice_request string
* @b12len: the invoice_request string length
* @b12: the invreq string
* @b12len: the invreq string length
* @our_features: if non-NULL, feature set to check against.
* @must_be_chain: if non-NULL, chain to enforce.
* @fail: pointer to descriptive error string, set if this returns NULL.
*
* Note: invoice_request doesn't always have a signature, so no checking is done!
* Note: invreq doesn't always have a signature, so no checking is done!
*/
struct tlv_invoice_request *invrequest_decode(const tal_t *ctx,
const char *b12, size_t b12len,
Expand Down Expand Up @@ -103,14 +103,20 @@ bool bolt12_check_signature(const struct tlv_field *fields,
bool bolt12_chain_matches(const struct bitcoin_blkid *chain,
const struct chainparams *must_be_chain);

/* Given an array of max_num_chains chains (or NULL == bitcoin), does
* it match? */
bool bolt12_chains_match(const struct bitcoin_blkid *chains,
size_t max_num_chains,
const struct chainparams *must_be_chain);

/* Given a basetime, when does period N start? */
u64 offer_period_start(u64 basetime, size_t n,
const struct tlv_offer_recurrence *recurrence);
const struct recurrence *recurrence);

/* Get the start and end of the payment window for period N. */
void offer_period_paywindow(const struct tlv_offer_recurrence *recurrence,
const struct tlv_offer_recurrence_paywindow *recurrence_paywindow,
const struct tlv_offer_recurrence_base *recurrence_base,
void offer_period_paywindow(const struct recurrence *recurrence,
const struct recurrence_paywindow *recurrence_paywindow,
const struct recurrence_base *recurrence_base,
u64 basetime, u64 period_idx,
u64 *period_start, u64 *period_end);

Expand Down
2 changes: 1 addition & 1 deletion common/test/run-bolt12_period.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ int main(int argc, char *argv[])
/* We deal in UTC; mktime() uses local time */
setenv("TZ", "", 1);
json_for_each_arr(i, t, toks) {
struct tlv_offer_recurrence recurrence;
struct recurrence recurrence;
int unit;
const jsmntok_t *exp;
u64 base, secs, n;
Expand Down
Loading

0 comments on commit 1e3cb01

Please sign in to comment.