Browse Source
Note the collapse of '+\s*' and the test cases from the spec. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>fix-mocks
Rusty Russell
4 years ago
4 changed files with 610 additions and 0 deletions
@ -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; |
|||
} |
@ -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 */ |
@ -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…
Reference in new issue