2021-12-04 12:23:56 +01:00
|
|
|
#include "config.h"
|
2022-10-17 02:35:31 +02:00
|
|
|
#include <assert.h>
|
2020-12-09 04:56:16 +01:00
|
|
|
#include <bitcoin/chainparams.h>
|
2021-09-16 07:00:42 +02:00
|
|
|
#include <ccan/tal/str/str.h>
|
2020-12-09 04:56:16 +01:00
|
|
|
#include <common/bech32_util.h>
|
|
|
|
#include <common/bolt12.h>
|
|
|
|
#include <common/bolt12_merkle.h>
|
2021-10-08 05:27:29 +02:00
|
|
|
#include <common/configdir.h>
|
2020-12-09 04:56:16 +01:00
|
|
|
#include <common/features.h>
|
|
|
|
#include <secp256k1_schnorrsig.h>
|
2020-12-16 04:13:19 +01:00
|
|
|
#include <time.h>
|
2020-12-09 04:56:16 +01:00
|
|
|
|
2021-11-30 04:06:05 +01:00
|
|
|
/* 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)
|
2020-12-09 04:56:16 +01:00
|
|
|
{
|
|
|
|
/* BOLT-offers #12:
|
|
|
|
* - if the chain for the invoice is not solely bitcoin:
|
|
|
|
* - MUST specify `chains` the offer is valid for.
|
|
|
|
* - otherwise:
|
|
|
|
* - the bitcoin chain is implied as the first and only entry.
|
|
|
|
*/
|
|
|
|
/* BOLT-offers #12:
|
|
|
|
* The reader of an invoice_request:
|
|
|
|
*...
|
2021-11-30 04:06:05 +01:00
|
|
|
* - if `chain` is not present:
|
|
|
|
* - MUST fail the request if bitcoin is not a supported chain.
|
|
|
|
* - otherwise:
|
|
|
|
* - MUST fail the request if `chain` is not a supported chain.
|
2020-12-09 04:56:16 +01:00
|
|
|
*/
|
2021-11-30 04:06:05 +01:00
|
|
|
if (!chains) {
|
|
|
|
max_num_chains = 1;
|
2020-12-09 04:56:16 +01:00
|
|
|
chains = &chainparams_for_network("bitcoin")->genesis_blockhash;
|
|
|
|
}
|
|
|
|
|
2021-11-30 04:06:05 +01:00
|
|
|
for (size_t i = 0; i < max_num_chains; i++) {
|
2020-12-09 04:56:16 +01:00
|
|
|
if (bitcoin_blkid_eq(&chains[i],
|
|
|
|
&must_be_chain->genesis_blockhash))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-08 05:27:29 +02:00
|
|
|
bool bolt12_chain_matches(const struct bitcoin_blkid *chain,
|
2021-11-30 04:06:05 +01:00
|
|
|
const struct chainparams *must_be_chain)
|
2021-10-08 05:27:29 +02:00
|
|
|
{
|
2021-11-30 04:06:05 +01:00
|
|
|
return bolt12_chains_match(chain, 1, must_be_chain);
|
2021-10-08 05:27:29 +02:00
|
|
|
}
|
|
|
|
|
2020-12-09 04:56:16 +01:00
|
|
|
static char *check_features_and_chain(const tal_t *ctx,
|
|
|
|
const struct feature_set *our_features,
|
|
|
|
const struct chainparams *must_be_chain,
|
|
|
|
const u8 *features,
|
2022-11-09 03:32:00 +01:00
|
|
|
enum feature_place fplace,
|
2021-11-30 04:06:05 +01:00
|
|
|
const struct bitcoin_blkid *chains,
|
|
|
|
size_t num_chains)
|
2020-12-09 04:56:16 +01:00
|
|
|
{
|
|
|
|
if (must_be_chain) {
|
2021-11-30 04:06:05 +01:00
|
|
|
if (!bolt12_chains_match(chains, num_chains, must_be_chain))
|
2020-12-09 04:56:16 +01:00
|
|
|
return tal_fmt(ctx, "wrong chain");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (our_features) {
|
2022-11-09 03:32:00 +01:00
|
|
|
int badf = features_unsupported(our_features, features, fplace);
|
2020-12-09 04:56:16 +01:00
|
|
|
if (badf != -1)
|
|
|
|
return tal_fmt(ctx, "unknown feature bit %i", badf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-01-07 19:48:47 +01:00
|
|
|
bool bolt12_check_signature(const struct tlv_field *fields,
|
|
|
|
const char *messagename,
|
|
|
|
const char *fieldname,
|
2022-10-17 02:37:05 +02:00
|
|
|
const struct pubkey *key,
|
2021-01-07 19:48:47 +01:00
|
|
|
const struct bip340sig *sig)
|
|
|
|
{
|
|
|
|
struct sha256 m, shash;
|
|
|
|
|
|
|
|
merkle_tlv(fields, &m);
|
|
|
|
sighash_from_merkle(messagename, fieldname, &m, &shash);
|
2022-10-17 02:35:31 +02:00
|
|
|
|
|
|
|
return check_schnorr_sig(&shash, &key->pubkey, sig);
|
2021-01-07 19:48:47 +01:00
|
|
|
}
|
|
|
|
|
2020-12-09 04:56:16 +01:00
|
|
|
static char *check_signature(const tal_t *ctx,
|
|
|
|
const struct tlv_field *fields,
|
|
|
|
const char *messagename,
|
|
|
|
const char *fieldname,
|
2022-10-17 02:37:05 +02:00
|
|
|
const struct pubkey *node_id,
|
2020-12-09 04:56:16 +01:00
|
|
|
const struct bip340sig *sig)
|
|
|
|
{
|
|
|
|
if (!node_id)
|
|
|
|
return tal_fmt(ctx, "Missing node_id");
|
|
|
|
if (!sig)
|
|
|
|
return tal_fmt(ctx, "Missing signature");
|
|
|
|
|
2021-01-07 19:48:47 +01:00
|
|
|
if (!bolt12_check_signature(fields,
|
|
|
|
messagename, fieldname, node_id, sig))
|
2020-12-09 04:56:16 +01:00
|
|
|
return tal_fmt(ctx, "Invalid signature");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const u8 *string_to_data(const tal_t *ctx,
|
|
|
|
const char *str,
|
|
|
|
size_t str_len,
|
|
|
|
const char *hrp_expected,
|
|
|
|
size_t *dlen,
|
|
|
|
char **fail)
|
|
|
|
{
|
|
|
|
char *hrp;
|
|
|
|
u8 *data;
|
|
|
|
char *bech32;
|
|
|
|
size_t bech32_len;
|
|
|
|
bool have_plus = false;
|
|
|
|
|
|
|
|
/* First we collapse +\s*, except at start/end. */
|
|
|
|
bech32 = tal_arr(tmpctx, char, str_len);
|
|
|
|
bech32_len = 0;
|
|
|
|
for (size_t i = 0; i < str_len; i++) {
|
|
|
|
if (i != 0 && i+1 != str_len && !have_plus && str[i] == '+') {
|
|
|
|
have_plus = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (have_plus && cisspace(str[i]))
|
|
|
|
continue;
|
|
|
|
have_plus = false;
|
|
|
|
bech32[bech32_len++] = str[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (have_plus) {
|
|
|
|
*fail = tal_fmt(ctx, "unfinished string");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!from_bech32_charset(ctx, bech32, bech32_len, &hrp, &data)) {
|
|
|
|
*fail = tal_fmt(ctx, "invalid bech32 string");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!streq(hrp, hrp_expected)) {
|
|
|
|
*fail = tal_fmt(ctx, "unexpected prefix %s", hrp);
|
|
|
|
data = tal_free(data);
|
|
|
|
} else
|
|
|
|
*dlen = tal_bytelen(data);
|
|
|
|
|
|
|
|
tal_free(hrp);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *offer_encode(const tal_t *ctx, const struct tlv_offer *offer_tlv)
|
|
|
|
{
|
|
|
|
u8 *wire;
|
|
|
|
|
|
|
|
wire = tal_arr(tmpctx, u8, 0);
|
2022-03-23 00:31:14 +01:00
|
|
|
towire_tlv_offer(&wire, offer_tlv);
|
2020-12-09 04:56:16 +01:00
|
|
|
|
|
|
|
return to_bech32_charset(ctx, "lno", wire);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tlv_offer *offer_decode(const tal_t *ctx,
|
|
|
|
const char *b12, size_t b12len,
|
|
|
|
const struct feature_set *our_features,
|
|
|
|
const struct chainparams *must_be_chain,
|
|
|
|
char **fail)
|
|
|
|
{
|
2022-03-23 00:31:14 +01:00
|
|
|
struct tlv_offer *offer;
|
2020-12-09 04:56:16 +01:00
|
|
|
const u8 *data;
|
|
|
|
size_t dlen;
|
|
|
|
|
|
|
|
data = string_to_data(tmpctx, b12, b12len, "lno", &dlen, fail);
|
|
|
|
if (!data)
|
2022-03-23 00:31:14 +01:00
|
|
|
return NULL;;
|
2020-12-09 04:56:16 +01:00
|
|
|
|
2022-03-23 00:31:14 +01:00
|
|
|
offer = fromwire_tlv_offer(ctx, &data, &dlen);
|
|
|
|
if (!offer) {
|
2020-12-09 04:56:16 +01:00
|
|
|
*fail = tal_fmt(ctx, "invalid offer data");
|
2022-03-23 00:31:14 +01:00
|
|
|
return NULL;
|
2020-12-09 04:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
*fail = check_features_and_chain(ctx,
|
|
|
|
our_features, must_be_chain,
|
|
|
|
offer->features,
|
2022-11-09 03:32:00 +01:00
|
|
|
BOLT12_OFFER_FEATURE,
|
2021-11-30 04:06:05 +01:00
|
|
|
offer->chains,
|
|
|
|
tal_count(offer->chains));
|
2020-12-09 04:56:16 +01:00
|
|
|
if (*fail)
|
|
|
|
return tal_free(offer);
|
|
|
|
|
2021-07-02 02:11:34 +02:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2020-12-09 04:56:16 +01:00
|
|
|
return offer;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *invrequest_encode(const tal_t *ctx, const struct tlv_invoice_request *invrequest_tlv)
|
|
|
|
{
|
|
|
|
u8 *wire;
|
|
|
|
|
|
|
|
wire = tal_arr(tmpctx, u8, 0);
|
2022-03-23 00:31:14 +01:00
|
|
|
towire_tlv_invoice_request(&wire, invrequest_tlv);
|
2020-12-09 04:56:16 +01:00
|
|
|
|
|
|
|
return to_bech32_charset(ctx, "lnr", wire);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tlv_invoice_request *invrequest_decode(const tal_t *ctx,
|
|
|
|
const char *b12, size_t b12len,
|
|
|
|
const struct feature_set *our_features,
|
|
|
|
const struct chainparams *must_be_chain,
|
|
|
|
char **fail)
|
|
|
|
{
|
2022-03-23 00:31:14 +01:00
|
|
|
struct tlv_invoice_request *invrequest;
|
2020-12-09 04:56:16 +01:00
|
|
|
const u8 *data;
|
|
|
|
size_t dlen;
|
|
|
|
|
|
|
|
data = string_to_data(tmpctx, b12, b12len, "lnr", &dlen, fail);
|
|
|
|
if (!data)
|
2022-03-23 00:31:14 +01:00
|
|
|
return NULL;
|
2020-12-09 04:56:16 +01:00
|
|
|
|
2022-03-23 00:31:14 +01:00
|
|
|
invrequest = fromwire_tlv_invoice_request(ctx, &data, &dlen);
|
|
|
|
if (!invrequest) {
|
2020-12-09 04:56:16 +01:00
|
|
|
*fail = tal_fmt(ctx, "invalid invoice_request data");
|
2022-03-23 00:31:14 +01:00
|
|
|
return NULL;
|
2020-12-09 04:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
*fail = check_features_and_chain(ctx,
|
|
|
|
our_features, must_be_chain,
|
|
|
|
invrequest->features,
|
2022-11-09 03:32:00 +01:00
|
|
|
BOLT12_INVREQ_FEATURE,
|
2021-11-30 04:06:05 +01:00
|
|
|
invrequest->chain, 1);
|
2020-12-09 04:56:16 +01:00
|
|
|
if (*fail)
|
|
|
|
return tal_free(invrequest);
|
|
|
|
|
|
|
|
return invrequest;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *invoice_encode(const tal_t *ctx, const struct tlv_invoice *invoice_tlv)
|
|
|
|
{
|
|
|
|
u8 *wire;
|
|
|
|
|
|
|
|
wire = tal_arr(tmpctx, u8, 0);
|
2022-03-23 00:31:14 +01:00
|
|
|
towire_tlv_invoice(&wire, invoice_tlv);
|
2020-12-09 04:56:16 +01:00
|
|
|
|
|
|
|
return to_bech32_charset(ctx, "lni", wire);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx,
|
|
|
|
const char *b12, size_t b12len,
|
|
|
|
const struct feature_set *our_features,
|
|
|
|
const struct chainparams *must_be_chain,
|
|
|
|
char **fail)
|
|
|
|
{
|
2022-03-23 00:31:14 +01:00
|
|
|
struct tlv_invoice *invoice;
|
2020-12-09 04:56:16 +01:00
|
|
|
const u8 *data;
|
|
|
|
size_t dlen;
|
|
|
|
|
|
|
|
data = string_to_data(tmpctx, b12, b12len, "lni", &dlen, fail);
|
|
|
|
if (!data)
|
2022-03-23 00:31:14 +01:00
|
|
|
return NULL;
|
2020-12-09 04:56:16 +01:00
|
|
|
|
2022-03-23 00:31:14 +01:00
|
|
|
invoice = fromwire_tlv_invoice(ctx, &data, &dlen);
|
|
|
|
if (!invoice) {
|
2020-12-09 04:56:16 +01:00
|
|
|
*fail = tal_fmt(ctx, "invalid invoice data");
|
2022-03-23 00:31:14 +01:00
|
|
|
return NULL;
|
2020-12-09 04:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
*fail = check_features_and_chain(ctx,
|
|
|
|
our_features, must_be_chain,
|
|
|
|
invoice->features,
|
2022-11-09 03:32:00 +01:00
|
|
|
BOLT12_INVOICE_FEATURE,
|
2021-11-30 04:06:05 +01:00
|
|
|
invoice->chain, 1);
|
2020-12-09 04:56:16 +01:00
|
|
|
if (*fail)
|
|
|
|
return tal_free(invoice);
|
|
|
|
|
|
|
|
return invoice;
|
|
|
|
}
|
|
|
|
|
2020-12-16 04:13:19 +01:00
|
|
|
static void add_days(struct tm *tm, u32 number)
|
|
|
|
{
|
|
|
|
tm->tm_mday += number;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_months(struct tm *tm, u32 number)
|
|
|
|
{
|
|
|
|
tm->tm_mon += number;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_years(struct tm *tm, u32 number)
|
|
|
|
{
|
|
|
|
tm->tm_year += number;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 time_change(u64 prevstart, u32 number,
|
|
|
|
void (*add_time)(struct tm *tm, u32 number),
|
|
|
|
bool day_const)
|
|
|
|
{
|
|
|
|
struct tm tm;
|
|
|
|
time_t prev = prevstart, ret;
|
|
|
|
|
|
|
|
tm = *gmtime(&prev);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
struct tm new_tm = tm;
|
|
|
|
add_time(&new_tm, number);
|
|
|
|
ret = mktime(&new_tm);
|
|
|
|
|
|
|
|
if (ret == (time_t)-1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If we overflowed that month, try one less. */
|
|
|
|
if (!day_const || new_tm.tm_mday == tm.tm_mday)
|
|
|
|
break;
|
|
|
|
tm.tm_mday--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 offer_period_start(u64 basetime, size_t n,
|
|
|
|
const struct tlv_offer_recurrence *recur)
|
|
|
|
{
|
2021-11-30 04:06:05 +01:00
|
|
|
/* BOLT-offers-recurrence #12:
|
2020-12-16 04:13:19 +01:00
|
|
|
* 1. A `time_unit` defining 0 (seconds), 1 (days), 2 (months),
|
|
|
|
* 3 (years).
|
|
|
|
*/
|
|
|
|
switch (recur->time_unit) {
|
|
|
|
case 0:
|
|
|
|
return basetime + recur->period * n;
|
|
|
|
case 1:
|
|
|
|
return time_change(basetime, recur->period * n, add_days, false);
|
|
|
|
case 2:
|
|
|
|
return time_change(basetime, recur->period * n, add_months, true);
|
|
|
|
case 3:
|
|
|
|
return time_change(basetime, recur->period * n, add_years, true);
|
|
|
|
default:
|
|
|
|
/* This is our offer, how did we get here? */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
u64 basetime, u64 period_idx,
|
|
|
|
u64 *start, u64 *end)
|
|
|
|
{
|
2021-11-30 04:06:05 +01:00
|
|
|
/* BOLT-offers-recurrence #12:
|
2020-12-16 04:13:19 +01:00
|
|
|
* - if the offer contains `recurrence_paywindow`:
|
|
|
|
*/
|
|
|
|
if (recurrence_paywindow) {
|
|
|
|
u64 pstart = offer_period_start(basetime, period_idx,
|
|
|
|
recurrence);
|
2021-11-30 04:06:05 +01:00
|
|
|
/* BOLT-offers-recurrence #12:
|
2020-12-16 04:13:19 +01:00
|
|
|
* - 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
|
|
|
|
* `seconds_before` seconds before that period start.
|
|
|
|
* - SHOULD NOT send an `invoice_request` for a period later
|
|
|
|
* than `seconds_after` seconds past that period start.
|
|
|
|
*/
|
|
|
|
*start = pstart - recurrence_paywindow->seconds_before;
|
|
|
|
*end = pstart + recurrence_paywindow->seconds_after;
|
|
|
|
|
|
|
|
/* First payment without recurrence_base, we give
|
|
|
|
* ourselves 60 seconds, since period will start
|
|
|
|
* now */
|
|
|
|
if (!recurrence_base && period_idx == 0
|
|
|
|
&& recurrence_paywindow->seconds_after < 60)
|
|
|
|
*end = pstart + 60;
|
|
|
|
} else {
|
2021-11-30 04:06:05 +01:00
|
|
|
/* BOLT-offers-recurrence #12:
|
2020-12-16 04:13:19 +01:00
|
|
|
* - otherwise:
|
|
|
|
* - SHOULD NOT send an `invoice_request` with
|
|
|
|
* `recurrence_counter` is non-zero for a period whose
|
|
|
|
* immediate predecessor has not yet begun.
|
|
|
|
*/
|
|
|
|
if (period_idx == 0)
|
|
|
|
*start = 0;
|
|
|
|
else
|
|
|
|
*start = offer_period_start(basetime, period_idx-1,
|
|
|
|
recurrence);
|
|
|
|
|
2021-11-30 04:06:05 +01:00
|
|
|
/* BOLT-offers-recurrence #12:
|
2020-12-16 04:13:19 +01:00
|
|
|
* - SHOULD NOT send an `invoice_request` for a period which
|
|
|
|
* has already passed.
|
|
|
|
*/
|
|
|
|
*end = offer_period_start(basetime, period_idx+1,
|
|
|
|
recurrence) - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-09 04:56:16 +01:00
|
|
|
struct tlv_invoice *invoice_decode(const tal_t *ctx,
|
|
|
|
const char *b12, size_t b12len,
|
|
|
|
const struct feature_set *our_features,
|
|
|
|
const struct chainparams *must_be_chain,
|
|
|
|
char **fail)
|
|
|
|
{
|
|
|
|
struct tlv_invoice *invoice;
|
|
|
|
|
|
|
|
invoice = invoice_decode_nosig(ctx, b12, b12len, our_features,
|
|
|
|
must_be_chain, fail);
|
|
|
|
if (invoice) {
|
|
|
|
*fail = check_signature(ctx, invoice->fields,
|
|
|
|
"invoice", "signature",
|
|
|
|
invoice->node_id, invoice->signature);
|
|
|
|
if (*fail)
|
|
|
|
invoice = tal_free(invoice);
|
|
|
|
}
|
|
|
|
return invoice;
|
|
|
|
}
|
2021-03-09 09:50:53 +01:00
|
|
|
|
2021-12-04 12:26:06 +01:00
|
|
|
static bool bolt12_has_invoice_prefix(const char *str)
|
2021-03-09 09:50:53 +01:00
|
|
|
{
|
|
|
|
return strstarts(str, "lni1") || strstarts(str, "LNI1");
|
|
|
|
}
|
|
|
|
|
2021-12-04 12:26:06 +01:00
|
|
|
static bool bolt12_has_request_prefix(const char *str)
|
2021-03-09 09:50:53 +01:00
|
|
|
{
|
|
|
|
return strstarts(str, "lnr1") || strstarts(str, "LNR1");
|
|
|
|
}
|
|
|
|
|
2021-12-04 12:26:06 +01:00
|
|
|
static bool bolt12_has_offer_prefix(const char *str)
|
2021-03-09 09:50:53 +01:00
|
|
|
{
|
|
|
|
return strstarts(str, "lno1") || strstarts(str, "LNO1");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool bolt12_has_prefix(const char *str)
|
|
|
|
{
|
|
|
|
return bolt12_has_invoice_prefix(str) || bolt12_has_offer_prefix(str) ||
|
|
|
|
bolt12_has_request_prefix(str);
|
|
|
|
}
|
2022-11-09 03:32:00 +01:00
|
|
|
|
|
|
|
/* Inclusive span of tlv range >= minfield and <= maxfield */
|
|
|
|
size_t tlv_span(const u8 *tlvstream, size_t minfield, size_t maxfield,
|
|
|
|
size_t *startp)
|
|
|
|
{
|
|
|
|
const u8 *cursor = tlvstream;
|
|
|
|
size_t tlvlen = tal_bytelen(tlvstream);
|
|
|
|
const u8 *start, *end;
|
|
|
|
|
|
|
|
start = end = NULL;
|
|
|
|
while (tlvlen) {
|
|
|
|
const u8 *before = cursor;
|
|
|
|
bigsize_t type = fromwire_bigsize(&cursor, &tlvlen);
|
|
|
|
bigsize_t len = fromwire_bigsize(&cursor, &tlvlen);
|
|
|
|
if (type >= minfield && start == NULL)
|
|
|
|
start = before;
|
|
|
|
if (type > maxfield)
|
|
|
|
break;
|
|
|
|
fromwire_pad(&cursor, &tlvlen, len);
|
|
|
|
end = cursor;
|
|
|
|
}
|
|
|
|
if (!start)
|
|
|
|
start = end;
|
|
|
|
|
|
|
|
if (startp)
|
|
|
|
*startp = start - tlvstream;
|
|
|
|
return end - start;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void calc_offer(const u8 *tlvstream, struct sha256 *id)
|
|
|
|
{
|
|
|
|
size_t start, len;
|
|
|
|
|
|
|
|
/* BOLT-offers #12:
|
|
|
|
* A writer of an offer:
|
|
|
|
* - MUST NOT set any tlv fields greater or equal to 80, or tlv field 0.
|
|
|
|
*/
|
|
|
|
len = tlv_span(tlvstream, 1, 79, &start);
|
|
|
|
sha256(id, tlvstream + start, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void offer_offer_id(const struct tlv_offer *offer, struct sha256 *id)
|
|
|
|
{
|
|
|
|
u8 *wire = tal_arr(tmpctx, u8, 0);
|
|
|
|
|
|
|
|
towire_tlv_offer(&wire, offer);
|
|
|
|
calc_offer(wire, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void invreq_offer_id(const struct tlv_invoice_request *invreq, struct sha256 *id)
|
|
|
|
{
|
|
|
|
u8 *wire = tal_arr(tmpctx, u8, 0);
|
|
|
|
|
|
|
|
towire_tlv_invoice_request(&wire, invreq);
|
|
|
|
calc_offer(wire, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void invoice_offer_id(const struct tlv_invoice *invoice, struct sha256 *id)
|
|
|
|
{
|
|
|
|
u8 *wire = tal_arr(tmpctx, u8, 0);
|
|
|
|
|
|
|
|
towire_tlv_invoice(&wire, invoice);
|
|
|
|
calc_offer(wire, id);
|
|
|
|
}
|
2022-11-09 03:32:00 +01:00
|
|
|
|
|
|
|
/* BOLT-offers #12:
|
|
|
|
* ## Requirements for Invoice Requests
|
|
|
|
*
|
|
|
|
* The writer:
|
|
|
|
* - if it is responding to an offer:
|
|
|
|
* - MUST copy all fields from the offer (including unknown fields).
|
|
|
|
*/
|
|
|
|
struct tlv_invoice_request *invoice_request_for_offer(const tal_t *ctx,
|
|
|
|
const struct tlv_offer *offer)
|
|
|
|
{
|
|
|
|
const u8 *cursor;
|
|
|
|
size_t max;
|
|
|
|
u8 *wire = tal_arr(tmpctx, u8, 0);
|
|
|
|
towire_tlv_offer(&wire, offer);
|
|
|
|
|
|
|
|
cursor = wire;
|
|
|
|
max = tal_bytelen(wire);
|
|
|
|
return fromwire_tlv_invoice_request(ctx, &cursor, &max);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare a new invoice based on an invoice_request.
|
|
|
|
*/
|
|
|
|
struct tlv_invoice *invoice_for_invreq(const tal_t *ctx,
|
|
|
|
const struct tlv_invoice_request *invreq)
|
|
|
|
{
|
|
|
|
const u8 *cursor;
|
|
|
|
size_t start, len;
|
|
|
|
u8 *wire = tal_arr(tmpctx, u8, 0);
|
|
|
|
towire_tlv_invoice_request(&wire, invreq);
|
|
|
|
|
|
|
|
/* BOLT-offers #12:
|
|
|
|
* A writer of an invoice:
|
|
|
|
* - MUST copy all non-signature fields from the invreq (including
|
|
|
|
* unknown fields).
|
|
|
|
*/
|
|
|
|
len = tlv_span(wire, 0, 159, &start);
|
|
|
|
cursor = wire + start;
|
|
|
|
return fromwire_tlv_invoice(ctx, &cursor, &len);
|
|
|
|
}
|
|
|
|
|