mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 22:45:27 +01:00
common/bolt12: encode/decode for bolt12 offer, invoice_request and invoice
Note the collapse of '+\s*' and the test cases from the spec. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
d3ef871833
commit
4d086e9939
4 changed files with 610 additions and 0 deletions
|
@ -9,6 +9,7 @@ COMMON_SRC_NOGEN := \
|
|||
common/bip32.c \
|
||||
common/blinding.c \
|
||||
common/bolt11.c \
|
||||
common/bolt12.c \
|
||||
common/channel_config.c \
|
||||
common/channel_id.c \
|
||||
common/coin_mvt.c \
|
||||
|
@ -87,6 +88,7 @@ endif
|
|||
COMMON_SRC_GEN := common/status_wiregen.c common/peer_status_wiregen.c
|
||||
|
||||
ifeq ($(EXPERIMENTAL_FEATURES),1)
|
||||
COMMON_SRC_NOGEN += common/bolt12.c
|
||||
COMMON_SRC_NOGEN += common/bolt12_merkle.c
|
||||
endif
|
||||
|
||||
|
|
299
common/bolt12.c
Normal file
299
common/bolt12.c
Normal file
|
@ -0,0 +1,299 @@
|
|||
#include <bitcoin/block.h>
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/bech32.h>
|
||||
#include <common/bech32_util.h>
|
||||
#include <common/bolt12.h>
|
||||
#include <common/bolt12_merkle.h>
|
||||
#include <common/features.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
bool bolt12_chains_match(const struct bitcoin_blkid *chains,
|
||||
const struct chainparams *must_be_chain)
|
||||
{
|
||||
size_t num_chains;
|
||||
|
||||
/* 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:
|
||||
*...
|
||||
* - MUST fail the request if `chains` does not include (or
|
||||
* imply) a supported chain.
|
||||
*/
|
||||
/* BOLT-offers #12:
|
||||
*
|
||||
* - if the chain for the invoice is not solely bitcoin:
|
||||
* - MUST specify `chains` the invoice is valid for.
|
||||
* - otherwise:
|
||||
* - the bitcoin chain is implied as the first and only entry.
|
||||
*/
|
||||
num_chains = tal_count(chains);
|
||||
if (num_chains == 0) {
|
||||
num_chains = 1;
|
||||
chains = &chainparams_for_network("bitcoin")->genesis_blockhash;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_chains; i++) {
|
||||
if (bitcoin_blkid_eq(&chains[i],
|
||||
&must_be_chain->genesis_blockhash))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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,
|
||||
const struct bitcoin_blkid *chains)
|
||||
{
|
||||
if (must_be_chain) {
|
||||
if (!bolt12_chains_match(chains, must_be_chain))
|
||||
return tal_fmt(ctx, "wrong chain");
|
||||
}
|
||||
|
||||
if (our_features) {
|
||||
int badf = features_unsupported(our_features, features,
|
||||
BOLT11_FEATURE);
|
||||
if (badf != -1)
|
||||
return tal_fmt(ctx, "unknown feature bit %i", badf);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *check_signature(const tal_t *ctx,
|
||||
const struct tlv_field *fields,
|
||||
const char *messagename,
|
||||
const char *fieldname,
|
||||
const struct pubkey32 *node_id,
|
||||
const struct bip340sig *sig)
|
||||
{
|
||||
struct sha256 m, shash;
|
||||
|
||||
if (!node_id)
|
||||
return tal_fmt(ctx, "Missing node_id");
|
||||
if (!sig)
|
||||
return tal_fmt(ctx, "Missing signature");
|
||||
|
||||
merkle_tlv(fields, &m);
|
||||
sighash_from_merkle(messagename, fieldname, &m, &shash);
|
||||
if (secp256k1_schnorrsig_verify(secp256k1_ctx,
|
||||
sig->u8,
|
||||
shash.u.u8,
|
||||
&node_id->pubkey) != 1)
|
||||
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);
|
||||
towire_offer(&wire, offer_tlv);
|
||||
|
||||
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)
|
||||
{
|
||||
struct tlv_offer *offer;
|
||||
|
||||
offer = offer_decode_nosig(ctx, b12, b12len,
|
||||
our_features, must_be_chain, fail);
|
||||
|
||||
if (offer) {
|
||||
*fail = check_signature(ctx, offer->fields,
|
||||
"offer", "signature",
|
||||
offer->node_id, offer->signature);
|
||||
if (*fail)
|
||||
offer = tal_free(offer);
|
||||
}
|
||||
return offer;
|
||||
}
|
||||
|
||||
struct tlv_offer *offer_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)
|
||||
{
|
||||
struct tlv_offer *offer = tlv_offer_new(ctx);
|
||||
const u8 *data;
|
||||
size_t dlen;
|
||||
|
||||
data = string_to_data(tmpctx, b12, b12len, "lno", &dlen, fail);
|
||||
if (!data)
|
||||
return tal_free(offer);
|
||||
|
||||
if (!fromwire_offer(&data, &dlen, offer)) {
|
||||
*fail = tal_fmt(ctx, "invalid offer data");
|
||||
return tal_free(offer);
|
||||
}
|
||||
|
||||
*fail = check_features_and_chain(ctx,
|
||||
our_features, must_be_chain,
|
||||
offer->features,
|
||||
offer->chains);
|
||||
if (*fail)
|
||||
return tal_free(offer);
|
||||
|
||||
return offer;
|
||||
}
|
||||
|
||||
char *invrequest_encode(const tal_t *ctx, const struct tlv_invoice_request *invrequest_tlv)
|
||||
{
|
||||
u8 *wire;
|
||||
|
||||
wire = tal_arr(tmpctx, u8, 0);
|
||||
towire_invoice_request(&wire, invrequest_tlv);
|
||||
|
||||
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)
|
||||
{
|
||||
struct tlv_invoice_request *invrequest = tlv_invoice_request_new(ctx);
|
||||
const u8 *data;
|
||||
size_t dlen;
|
||||
|
||||
data = string_to_data(tmpctx, b12, b12len, "lnr", &dlen, fail);
|
||||
if (!data)
|
||||
return tal_free(invrequest);
|
||||
|
||||
if (!fromwire_invoice_request(&data, &dlen, invrequest)) {
|
||||
*fail = tal_fmt(ctx, "invalid invoice_request data");
|
||||
return tal_free(invrequest);
|
||||
}
|
||||
|
||||
*fail = check_features_and_chain(ctx,
|
||||
our_features, must_be_chain,
|
||||
invrequest->features,
|
||||
invrequest->chains);
|
||||
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);
|
||||
towire_invoice(&wire, invoice_tlv);
|
||||
|
||||
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)
|
||||
{
|
||||
struct tlv_invoice *invoice = tlv_invoice_new(ctx);
|
||||
const u8 *data;
|
||||
size_t dlen;
|
||||
|
||||
data = string_to_data(tmpctx, b12, b12len, "lni", &dlen, fail);
|
||||
if (!data)
|
||||
return tal_free(invoice);
|
||||
|
||||
if (!fromwire_invoice(&data, &dlen, invoice)) {
|
||||
*fail = tal_fmt(ctx, "invalid invoice data");
|
||||
return tal_free(invoice);
|
||||
}
|
||||
|
||||
*fail = check_features_and_chain(ctx,
|
||||
our_features, must_be_chain,
|
||||
invoice->features,
|
||||
invoice->chains);
|
||||
if (*fail)
|
||||
return tal_free(invoice);
|
||||
|
||||
return invoice;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
92
common/bolt12.h
Normal file
92
common/bolt12.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
#ifndef LIGHTNING_COMMON_BOLT12_H
|
||||
#define LIGHTNING_COMMON_BOLT12_H
|
||||
#include "config.h"
|
||||
#include <wire/bolt12_exp_wiregen.h>
|
||||
|
||||
struct feature_set;
|
||||
|
||||
/**
|
||||
* offer_encode - encode this complete bolt12 offer TLV into text.
|
||||
*/
|
||||
char *offer_encode(const tal_t *ctx, const struct tlv_offer *bolt12_tlv);
|
||||
|
||||
/**
|
||||
* offer_decode - decode this complete bolt12 text into a TLV.
|
||||
* @ctx: the context to allocate return or *@fail off.
|
||||
* @b12: the offer string
|
||||
* @b12len: the offer 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: checks signature!
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Variant which does not check signature */
|
||||
struct tlv_offer *offer_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);
|
||||
|
||||
/**
|
||||
* invrequest_encode - encode this complete bolt12 invreq TLV into text.
|
||||
*/
|
||||
char *invrequest_encode(const tal_t *ctx,
|
||||
const struct tlv_invoice_request *bolt12_tlv);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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!
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* invoice_encode - encode this complete bolt12 invoice TLV into text.
|
||||
*/
|
||||
char *invoice_encode(const tal_t *ctx, const struct tlv_invoice *bolt12_tlv);
|
||||
|
||||
/**
|
||||
* invoice_decode - decode this complete bolt12 text into a TLV.
|
||||
* @ctx: the context to allocate return or *@fail off.
|
||||
* @b12: the invoice string
|
||||
* @b12len: the invoice 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: checks signature!
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Variant which does not check signature */
|
||||
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);
|
||||
|
||||
/* Given a tal_arr of chains, does it contain this chain? */
|
||||
bool bolt12_chains_match(const struct bitcoin_blkid *chains,
|
||||
const struct chainparams *must_be_chain);
|
||||
|
||||
#endif /* LIGHTNING_COMMON_BOLT12_H */
|
217
common/test/exp-run-bolt12_decode.c
Normal file
217
common/test/exp-run-bolt12_decode.c
Normal file
|
@ -0,0 +1,217 @@
|
|||
#include "config.h"
|
||||
#include "../bolt12.c"
|
||||
#include "../bech32_util.c"
|
||||
#include "../bech32.c"
|
||||
#include "../json.c"
|
||||
#include <assert.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/tal/grab_file/grab_file.h>
|
||||
#include <ccan/tal/path/path.h>
|
||||
|
||||
/* AUTOGENERATED MOCKS START */
|
||||
/* Generated stub for amount_asset_is_main */
|
||||
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
|
||||
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
|
||||
/* Generated stub for amount_asset_to_sat */
|
||||
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
|
||||
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
|
||||
/* Generated stub for amount_sat */
|
||||
struct amount_sat amount_sat(u64 satoshis UNNEEDED)
|
||||
{ fprintf(stderr, "amount_sat called!\n"); abort(); }
|
||||
/* Generated stub for amount_sat_add */
|
||||
bool amount_sat_add(struct amount_sat *val UNNEEDED,
|
||||
struct amount_sat a UNNEEDED,
|
||||
struct amount_sat b UNNEEDED)
|
||||
{ fprintf(stderr, "amount_sat_add called!\n"); abort(); }
|
||||
/* Generated stub for amount_sat_eq */
|
||||
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
|
||||
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
|
||||
/* Generated stub for amount_sat_greater_eq */
|
||||
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
|
||||
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
|
||||
/* Generated stub for amount_sat_sub */
|
||||
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
|
||||
struct amount_sat a UNNEEDED,
|
||||
struct amount_sat b UNNEEDED)
|
||||
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
|
||||
/* Generated stub for amount_sat_to_asset */
|
||||
struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u8 *asset UNNEEDED)
|
||||
{ fprintf(stderr, "amount_sat_to_asset called!\n"); abort(); }
|
||||
/* Generated stub for amount_tx_fee */
|
||||
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
|
||||
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
|
||||
/* 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_amount_sat */
|
||||
struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_amount_sat 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_invoice */
|
||||
bool fromwire_invoice(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||
struct tlv_invoice * record UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_invoice called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_invoice_request */
|
||||
bool fromwire_invoice_request(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||
struct tlv_invoice_request * record UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_invoice_request called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_offer */
|
||||
bool fromwire_offer(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||
struct tlv_offer * record UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_offer 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_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 json_add_member */
|
||||
void json_add_member(struct json_stream *js UNNEEDED,
|
||||
const char *fieldname UNNEEDED,
|
||||
bool quote UNNEEDED,
|
||||
const char *fmt UNNEEDED, ...)
|
||||
{ fprintf(stderr, "json_add_member called!\n"); abort(); }
|
||||
/* Generated stub for json_member_direct */
|
||||
char *json_member_direct(struct json_stream *js UNNEEDED,
|
||||
const char *fieldname UNNEEDED, size_t extra UNNEEDED)
|
||||
{ fprintf(stderr, "json_member_direct 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 tlv_invoice_new */
|
||||
struct tlv_invoice *tlv_invoice_new(const tal_t *ctx UNNEEDED)
|
||||
{ fprintf(stderr, "tlv_invoice_new called!\n"); abort(); }
|
||||
/* Generated stub for tlv_invoice_request_new */
|
||||
struct tlv_invoice_request *tlv_invoice_request_new(const tal_t *ctx UNNEEDED)
|
||||
{ fprintf(stderr, "tlv_invoice_request_new called!\n"); abort(); }
|
||||
/* Generated stub for tlv_offer_new */
|
||||
struct tlv_offer *tlv_offer_new(const tal_t *ctx UNNEEDED)
|
||||
{ fprintf(stderr, "tlv_offer_new called!\n"); abort(); }
|
||||
/* Generated stub for towire */
|
||||
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
|
||||
{ fprintf(stderr, "towire called!\n"); abort(); }
|
||||
/* Generated stub for towire_amount_sat */
|
||||
void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED)
|
||||
{ fprintf(stderr, "towire_amount_sat called!\n"); abort(); }
|
||||
/* Generated stub for towire_bool */
|
||||
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
|
||||
/* Generated stub for towire_invoice */
|
||||
void towire_invoice(u8 **pptr UNNEEDED, const struct tlv_invoice *record UNNEEDED)
|
||||
{ fprintf(stderr, "towire_invoice called!\n"); abort(); }
|
||||
/* Generated stub for towire_invoice_request */
|
||||
void towire_invoice_request(u8 **pptr UNNEEDED, const struct tlv_invoice_request *record UNNEEDED)
|
||||
{ fprintf(stderr, "towire_invoice_request called!\n"); abort(); }
|
||||
/* Generated stub for towire_offer */
|
||||
void towire_offer(u8 **pptr UNNEEDED, const struct tlv_offer *record UNNEEDED)
|
||||
{ fprintf(stderr, "towire_offer called!\n"); abort(); }
|
||||
/* Generated stub for towire_secp256k1_ecdsa_signature */
|
||||
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
|
||||
const secp256k1_ecdsa_signature *signature UNNEEDED)
|
||||
{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); }
|
||||
/* Generated stub for towire_sha256 */
|
||||
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
|
||||
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u16 */
|
||||
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u32 */
|
||||
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u64 */
|
||||
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u8 */
|
||||
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u8_array */
|
||||
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *json;
|
||||
size_t i;
|
||||
jsmn_parser parser;
|
||||
jsmntok_t toks[5000];
|
||||
const jsmntok_t *t;
|
||||
|
||||
setup_locale();
|
||||
setup_tmpctx();
|
||||
|
||||
if (argv[1])
|
||||
json = grab_file(tmpctx, argv[1]);
|
||||
else {
|
||||
char *dir = getenv("BOLTDIR");
|
||||
json = grab_file(tmpctx,
|
||||
path_join(tmpctx,
|
||||
dir ? dir : "../lightning-rfc",
|
||||
"bolt12/format-string-test.json"));
|
||||
if (!json) {
|
||||
printf("test file not found, skipping\n");
|
||||
tal_free(tmpctx);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
jsmn_init(&parser);
|
||||
if (jsmn_parse(&parser, json, strlen(json), toks, ARRAY_SIZE(toks)) < 0)
|
||||
abort();
|
||||
|
||||
json_for_each_arr(i, t, toks) {
|
||||
bool valid, actual;
|
||||
const jsmntok_t *strtok;
|
||||
char *fail;
|
||||
const char *str;
|
||||
size_t dlen;
|
||||
struct json_escape *esc;
|
||||
|
||||
json_to_bool(json, json_get_member(json, t, "valid"), &valid);
|
||||
strtok = json_get_member(json, t, "string");
|
||||
esc = json_escape_string_(tmpctx, json + strtok->start,
|
||||
strtok->end - strtok->start);
|
||||
str = json_escape_unescape(tmpctx, esc);
|
||||
actual = (string_to_data(tmpctx, str, strlen(str),
|
||||
"lni", &dlen, &fail) != NULL);
|
||||
assert(actual == valid);
|
||||
}
|
||||
tal_free(tmpctx);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue