mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 15:00:34 +01:00
This is a final sweep to match the current BOLT12 text: 1563d13999d342680140c693de0b9d65aa522372 ("More bolt12 test vectors.") Only two code changes, to change the order of checks to match the bolt, and to give a warning on decode if a path is empty. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
213 lines
9.2 KiB
C
213 lines
9.2 KiB
C
/* Pipe through jq to create format-string-test.json */
|
|
#include "config.h"
|
|
#include <assert.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ccan/tal/grab_file/grab_file.h>
|
|
#include <ccan/tal/path/path.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <common/bolt12.h>
|
|
#include <common/bolt12_merkle.h>
|
|
#include <common/features.h>
|
|
#include <common/setup.h>
|
|
|
|
/* AUTOGENERATED MOCKS START */
|
|
/* Generated stub for features_unsupported */
|
|
int features_unsupported(const struct feature_set *our_features UNNEEDED,
|
|
const u8 *their_features UNNEEDED,
|
|
enum feature_place p UNNEEDED)
|
|
{ fprintf(stderr, "features_unsupported called!\n"); abort(); }
|
|
/* Generated stub for fromwire */
|
|
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
|
|
{ fprintf(stderr, "fromwire called!\n"); abort(); }
|
|
/* Generated stub for fromwire_blinded_path */
|
|
struct blinded_path *fromwire_blinded_path(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_blinded_path called!\n"); abort(); }
|
|
/* Generated stub for fromwire_bool */
|
|
bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_bool called!\n"); abort(); }
|
|
/* Generated stub for fromwire_fail */
|
|
void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
|
|
/* Generated stub for fromwire_pad */
|
|
void fromwire_pad(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_pad called!\n"); abort(); }
|
|
/* Generated stub for fromwire_secp256k1_ecdsa_signature */
|
|
void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
|
secp256k1_ecdsa_signature *signature UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); }
|
|
/* Generated stub for fromwire_sha256 */
|
|
void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_tal_arrn */
|
|
u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
|
|
const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); }
|
|
/* Generated stub for fromwire_tu32 */
|
|
u32 fromwire_tu32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_tu32 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_tu64 */
|
|
u64 fromwire_tu64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_tu64 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_u16 */
|
|
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_u32 */
|
|
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_u64 */
|
|
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_u8 */
|
|
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
|
|
/* Generated stub for fromwire_u8_array */
|
|
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
|
|
/* Generated stub for fromwire_utf8_array */
|
|
void fromwire_utf8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, char *arr UNNEEDED, size_t num UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_utf8_array called!\n"); abort(); }
|
|
/* Generated stub for merkle_tlv */
|
|
void merkle_tlv(const struct tlv_field *fields UNNEEDED, struct sha256 *merkle UNNEEDED)
|
|
{ fprintf(stderr, "merkle_tlv called!\n"); abort(); }
|
|
/* Generated stub for sighash_from_merkle */
|
|
void sighash_from_merkle(const char *messagename UNNEEDED,
|
|
const char *fieldname UNNEEDED,
|
|
const struct sha256 *merkle UNNEEDED,
|
|
struct sha256 *sighash UNNEEDED)
|
|
{ fprintf(stderr, "sighash_from_merkle called!\n"); abort(); }
|
|
/* Generated stub for towire_blinded_path */
|
|
void towire_blinded_path(u8 **p UNNEEDED, const struct blinded_path *blinded_path UNNEEDED)
|
|
{ fprintf(stderr, "towire_blinded_path called!\n"); abort(); }
|
|
/* AUTOGENERATED MOCKS END */
|
|
|
|
static void example2(const char *comment, bool valid,
|
|
const char *str, bool final)
|
|
{
|
|
printf("{\n");
|
|
printf("\"comment\": \"%s\",\n", comment);
|
|
printf("\"valid\": %s,\n", valid ? "true": "false");
|
|
printf("\"string\": \"%s\"\n", str);
|
|
printf("}%s\n", final ? "" : ",");
|
|
}
|
|
|
|
static void example(const char *comment, bool valid, const char *str)
|
|
{
|
|
example2(comment, valid, str, false);
|
|
}
|
|
|
|
static void example_final(const char *comment, bool valid, const char *str)
|
|
{
|
|
example2(comment, valid, str, true);
|
|
}
|
|
|
|
static utf8 *tal_utf8(const tal_t *ctx, const char *str)
|
|
{
|
|
/* Non-NUL terminated! */
|
|
return tal_dup_arr(ctx, char, str, strlen(str), 0);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct tlv_offer *offer;
|
|
struct secret alice;
|
|
char *str;
|
|
|
|
common_setup(argv[0]);
|
|
|
|
offer = tlv_offer_new(tmpctx);
|
|
/* BOLT-offers #12:
|
|
* A writer of an offer:
|
|
* - MUST NOT set any TLV fields outside the inclusive ranges: 1 to 79 and 1000000000 to 1999999999.
|
|
* - if the chain for the invoice is not solely bitcoin:
|
|
* - MUST specify `offer_chains` the offer is valid for.
|
|
* - otherwise:
|
|
* - MAY omit `offer_chains`, implying that bitcoin is only chain.
|
|
* - if a specific minimum `offer_amount` is required for successful payment:
|
|
* - MUST set `offer_amount` to the amount expected (per item).
|
|
* - if the currency for `offer_amount` is that of all entries in `chains`:
|
|
* - MUST specify `amount` in multiples of the minimum lightning-payable unit
|
|
* (e.g. milli-satoshis for bitcoin).
|
|
* - otherwise:
|
|
* - MUST specify `offer_currency` `iso4217` as an ISO 4712 three-letter code.
|
|
* - MUST specify `offer_amount` in the currency unit adjusted by the ISO 4712
|
|
* exponent (e.g. USD cents).
|
|
* - MUST set `offer_description` to a complete description of the purpose
|
|
* of the payment.
|
|
* - otherwise:
|
|
* - MUST NOT set `offer_amount`
|
|
* - MUST NOT set `offer_currency`
|
|
* - MAY set `offer_description`
|
|
* - MAY set `offer_metadata` for its own use.
|
|
* - if it supports bolt12 offer features:
|
|
* - MUST set `offer_features`.`features` to the bitmap of bolt12 features.
|
|
* - if the offer expires:
|
|
* - MUST set `offer_absolute_expiry` `seconds_from_epoch` to the number of seconds
|
|
* after midnight 1 January 1970, UTC that invoice_request should not be
|
|
* attempted.
|
|
* - if it is connected only by private channels:
|
|
* - MUST include `offer_paths` containing one or more paths to the node from
|
|
* publicly reachable nodes.
|
|
* - otherwise:
|
|
* - MAY include `offer_paths`.
|
|
* - if it includes `offer_paths`:
|
|
* - SHOULD ignore any invoice_request which does not use the path.
|
|
* - MAY set `offer_issuer_id`.
|
|
* - otherwise:
|
|
* - MUST set `offer_issuer_id` to the node's public key to request the invoice from.
|
|
* - if it sets `offer_issuer`:
|
|
* - SHOULD set it to identify the issuer of the invoice clearly.
|
|
* - if it includes a domain name:
|
|
* - SHOULD begin it with either user@domain or domain
|
|
* - MAY follow with a space and more text
|
|
* - if it can supply more than one item for a single invoice:
|
|
* - if the maximum quantity is known:
|
|
* - MUST set that maximum in `offer_quantity_max`.
|
|
* - MUST NOT set `offer_quantity_max` to 0.
|
|
* - otherwise:
|
|
* - MUST set `offer_quantity_max` to 0.
|
|
* - otherwise:
|
|
* - MUST NOT set `offer_quantity_max`.
|
|
*/
|
|
memset(&alice, 'A', sizeof(alice));
|
|
offer->offer_issuer_id = tal(offer, struct pubkey);
|
|
assert(pubkey_from_secret(&alice, offer->offer_issuer_id));
|
|
offer->offer_description = tal_utf8(offer, "An example description");
|
|
offer->offer_issuer = tal_utf8(offer, "BOLT 12 industries");
|
|
offer->offer_amount = tal(offer, u64);
|
|
/* 1M msat */
|
|
*offer->offer_amount = 1000000;
|
|
|
|
str = offer_encode(tmpctx, offer);
|
|
printf("[\n");
|
|
|
|
example("A complete string is valid", true, str);
|
|
example("+ can join anywhere", true,
|
|
tal_fmt(tmpctx, "%.*s+%s", 1, str, str + 1));
|
|
example("Multiple + can join", true,
|
|
tal_fmt(tmpctx, "%.*s+%.*s+%.*s+%.*s+%s",
|
|
15, str,
|
|
31, str + 15,
|
|
18, str + 15 + 31,
|
|
70, str + 15 + 31 + 18,
|
|
str + 15 + 31 + 18 + 70));
|
|
example("+ can be followed by whitespace", true,
|
|
tal_fmt(tmpctx, "%.*s+ %.*s+ %.*s+\\n%.*s+\\r\\n %s",
|
|
15, str,
|
|
31, str + 15,
|
|
18, str + 15 + 31,
|
|
70, str + 15 + 31 + 18,
|
|
str + 15 + 31 + 18 + 70));
|
|
|
|
example("+ must be surrounded by bech32 characters", false,
|
|
tal_fmt(tmpctx, "%s+", str));
|
|
example("+ must be surrounded by bech32 characters", false,
|
|
tal_fmt(tmpctx, "%s+ ", str));
|
|
example("+ must be surrounded by bech32 characters", false,
|
|
tal_fmt(tmpctx, "+%s", str));
|
|
example("+ must be surrounded by bech32 characters", false,
|
|
tal_fmt(tmpctx, "+ %s", str));
|
|
example_final("+ must be surrounded by bech32 characters", false,
|
|
tal_fmt(tmpctx, "%.*s++%s", 2, str, str+2));
|
|
printf("]\n");
|
|
common_shutdown();
|
|
}
|