Browse Source

common/bolt11_json: extract bolt11->json code.

Our new "decode" command will also handle bolt11.  We make a few cleanups:

1. Avoid type_to_string() in JSON, instead use format functions directly.
2. Don't need to escape description now that JSON core does that for us.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa
Rusty Russell 4 years ago
parent
commit
84dc943cf5
  1. 5
      bitcoin/signature.c
  2. 1
      bitcoin/signature.h
  3. 1
      common/Makefile
  4. 3
      common/bolt11.c
  5. 129
      common/bolt11_json.c
  6. 10
      common/bolt11_json.h
  7. 4
      common/test/run-bolt11.c
  8. 1
      lightningd/Makefile
  9. 123
      lightningd/invoice.c
  10. 1
      lightningd/peer_control.c
  11. 9
      lightningd/test/run-invoice-select-inchan.c

5
bitcoin/signature.c

@ -310,8 +310,7 @@ bool signature_from_der(const u8 *der, size_t len, struct bitcoin_signature *sig
return true; return true;
} }
static char *signature_to_hexstr(const tal_t *ctx, char *fmt_signature(const tal_t *ctx, const secp256k1_ecdsa_signature *sig)
const secp256k1_ecdsa_signature *sig)
{ {
u8 der[72]; u8 der[72];
size_t len = 72; size_t len = 72;
@ -321,7 +320,7 @@ static char *signature_to_hexstr(const tal_t *ctx,
return tal_hexstr(ctx, der, len); return tal_hexstr(ctx, der, len);
} }
REGISTER_TYPE_TO_STRING(secp256k1_ecdsa_signature, signature_to_hexstr); REGISTER_TYPE_TO_STRING(secp256k1_ecdsa_signature, fmt_signature);
static char *bitcoin_signature_to_hexstr(const tal_t *ctx, static char *bitcoin_signature_to_hexstr(const tal_t *ctx,
const struct bitcoin_signature *sig) const struct bitcoin_signature *sig)

1
bitcoin/signature.h

@ -142,6 +142,7 @@ void fromwire_bip340sig(const u8 **cursor, size_t *max,
struct bip340sig *bip340sig); struct bip340sig *bip340sig);
/* Get a hex string sig */ /* Get a hex string sig */
char *fmt_signature(const tal_t *ctx, const secp256k1_ecdsa_signature *sig);
char *fmt_bip340sig(const tal_t *ctx, const struct bip340sig *bip340sig); char *fmt_bip340sig(const tal_t *ctx, const struct bip340sig *bip340sig);
/* For caller convenience, we hand in tag in parts (any can be "") */ /* For caller convenience, we hand in tag in parts (any can be "") */

1
common/Makefile

@ -9,6 +9,7 @@ COMMON_SRC_NOGEN := \
common/bip32.c \ common/bip32.c \
common/blinding.c \ common/blinding.c \
common/bolt11.c \ common/bolt11.c \
common/bolt11_json.c \
common/bolt12.c \ common/bolt12.c \
common/channel_config.c \ common/channel_config.c \
common/channel_id.c \ common/channel_id.c \

3
common/bolt11.c

@ -297,8 +297,7 @@ static char *decode_n(struct bolt11 *b11,
data_length * 5, false); data_length * 5, false);
if (!node_id_valid(&b11->receiver_id)) if (!node_id_valid(&b11->receiver_id))
return tal_fmt(b11, "n: invalid pubkey %s", return tal_fmt(b11, "n: invalid pubkey %s",
type_to_string(tmpctx, struct node_id, node_id_to_hexstr(tmpctx, &b11->receiver_id));
&b11->receiver_id));
*have_n = true; *have_n = true;
return NULL; return NULL;

129
common/bolt11_json.c

@ -0,0 +1,129 @@
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/chainparams.h>
#include <bitcoin/script.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/bolt11_json.h>
#include <common/json.h>
#include <common/json_helpers.h>
#include <common/json_stream.h>
static void json_add_fallback(struct json_stream *response,
const char *fieldname,
const u8 *fallback,
const struct chainparams *chain)
{
struct bitcoin_address pkh;
struct ripemd160 sh;
struct sha256 wsh;
json_object_start(response, fieldname);
if (is_p2pkh(fallback, &pkh)) {
json_add_string(response, "type", "P2PKH");
json_add_string(response, "addr",
bitcoin_to_base58(tmpctx, chain, &pkh));
} else if (is_p2sh(fallback, &sh)) {
json_add_string(response, "type", "P2SH");
json_add_string(response, "addr",
p2sh_to_base58(tmpctx, chain, &sh));
} else if (is_p2wpkh(fallback, &pkh)) {
char out[73 + strlen(chain->bip173_name)];
json_add_string(response, "type", "P2WPKH");
if (segwit_addr_encode(out, chain->bip173_name, 0,
(const u8 *)&pkh, sizeof(pkh)))
json_add_string(response, "addr", out);
} else if (is_p2wsh(fallback, &wsh)) {
char out[73 + strlen(chain->bip173_name)];
json_add_string(response, "type", "P2WSH");
if (segwit_addr_encode(out, chain->bip173_name, 0,
(const u8 *)&wsh, sizeof(wsh)))
json_add_string(response, "addr", out);
}
json_add_hex_talarr(response, "hex", fallback);
json_object_end(response);
}
void json_add_bolt11(struct json_stream *response,
const struct bolt11 *b11)
{
json_add_string(response, "currency", b11->chain->bip173_name);
json_add_u64(response, "created_at", b11->timestamp);
json_add_u64(response, "expiry", b11->expiry);
json_add_node_id(response, "payee", &b11->receiver_id);
if (b11->msat)
json_add_amount_msat_compat(response, *b11->msat,
"msatoshi", "amount_msat");
if (b11->description)
json_add_string(response, "description", b11->description);
if (b11->description_hash)
json_add_sha256(response, "description_hash",
b11->description_hash);
json_add_num(response, "min_final_cltv_expiry",
b11->min_final_cltv_expiry);
if (b11->payment_secret)
json_add_secret(response, "payment_secret",
b11->payment_secret);
if (b11->features)
json_add_hex_talarr(response, "features", b11->features);
if (tal_count(b11->fallbacks)) {
json_array_start(response, "fallbacks");
for (size_t i = 0; i < tal_count(b11->fallbacks); i++)
json_add_fallback(response, NULL,
b11->fallbacks[i], b11->chain);
json_array_end(response);
}
if (tal_count(b11->routes)) {
size_t i, n;
json_array_start(response, "routes");
for (i = 0; i < tal_count(b11->routes); i++) {
json_array_start(response, NULL);
for (n = 0; n < tal_count(b11->routes[i]); n++) {
json_object_start(response, NULL);
json_add_node_id(response, "pubkey",
&b11->routes[i][n].pubkey);
json_add_short_channel_id(response,
"short_channel_id",
&b11->routes[i][n]
.short_channel_id);
json_add_u64(response, "fee_base_msat",
b11->routes[i][n].fee_base_msat);
json_add_u64(response, "fee_proportional_millionths",
b11->routes[i][n].fee_proportional_millionths);
json_add_num(response, "cltv_expiry_delta",
b11->routes[i][n]
.cltv_expiry_delta);
json_object_end(response);
}
json_array_end(response);
}
json_array_end(response);
}
if (!list_empty(&b11->extra_fields)) {
struct bolt11_field *extra;
json_array_start(response, "extra");
list_for_each(&b11->extra_fields, extra, list) {
char *data = tal_arr(NULL, char, tal_count(extra->data)+1);
size_t i;
for (i = 0; i < tal_count(extra->data); i++)
data[i] = bech32_charset[extra->data[i]];
data[i] = '\0';
json_object_start(response, NULL);
json_add_string(response, "tag",
tal_fmt(data, "%c", extra->tag));
json_add_string(response, "data", data);
tal_free(data);
json_object_end(response);
}
json_array_end(response);
}
json_add_sha256(response, "payment_hash", &b11->payment_hash);
json_add_string(response, "signature", fmt_signature(tmpctx, &b11->sig));
}

10
common/bolt11_json.h

@ -0,0 +1,10 @@
#ifndef LIGHTNING_COMMON_BOLT11_JSON_H
#define LIGHTNING_COMMON_BOLT11_JSON_H
#include "config.h"
struct bolt11;
struct json_stream;
void json_add_bolt11(struct json_stream *response,
const struct bolt11 *b11);
#endif /* LIGHTNING_COMMON_BOLT11_JSON_H */

4
common/test/run-bolt11.c

@ -16,10 +16,6 @@
#include <wally_core.h> #include <wally_core.h>
/* AUTOGENERATED MOCKS START */ /* AUTOGENERATED MOCKS START */
/* Generated stub for type_to_string_ */
const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED,
union printable_types u UNNEEDED)
{ fprintf(stderr, "type_to_string_ called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */ /* AUTOGENERATED MOCKS END */
static struct privkey privkey; static struct privkey privkey;

1
lightningd/Makefile

@ -76,6 +76,7 @@ LIGHTNINGD_COMMON_OBJS := \
common/bip32.o \ common/bip32.o \
common/blinding.o \ common/blinding.o \
common/bolt11.o \ common/bolt11.o \
common/bolt11_json.o \
common/channel_id.o \ common/channel_id.o \
common/channel_config.o \ common/channel_config.o \
common/coin_mvt.o \ common/coin_mvt.o \

123
lightningd/invoice.c

@ -1,7 +1,4 @@
#include "invoice.h" #include "invoice.h"
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h> #include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h> #include <ccan/asort/asort.h>
#include <ccan/json_escape/json_escape.h> #include <ccan/json_escape/json_escape.h>
@ -10,6 +7,7 @@
#include <common/amount.h> #include <common/amount.h>
#include <common/bech32.h> #include <common/bech32.h>
#include <common/bolt11.h> #include <common/bolt11.h>
#include <common/bolt11_json.h>
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
#include <common/bolt12.h> #include <common/bolt12.h>
#include <common/bolt12_merkle.h> #include <common/bolt12_merkle.h>
@ -1391,41 +1389,6 @@ static const struct json_command waitinvoice_command = {
}; };
AUTODATA(json_command, &waitinvoice_command); AUTODATA(json_command, &waitinvoice_command);
static void json_add_fallback(struct json_stream *response,
const char *fieldname,
const u8 *fallback,
const struct chainparams *chain)
{
struct bitcoin_address pkh;
struct ripemd160 sh;
struct sha256 wsh;
json_object_start(response, fieldname);
if (is_p2pkh(fallback, &pkh)) {
json_add_string(response, "type", "P2PKH");
json_add_string(response, "addr",
bitcoin_to_base58(tmpctx, chain, &pkh));
} else if (is_p2sh(fallback, &sh)) {
json_add_string(response, "type", "P2SH");
json_add_string(response, "addr",
p2sh_to_base58(tmpctx, chain, &sh));
} else if (is_p2wpkh(fallback, &pkh)) {
char out[73 + strlen(chain->bip173_name)];
json_add_string(response, "type", "P2WPKH");
if (segwit_addr_encode(out, chain->bip173_name, 0,
(const u8 *)&pkh, sizeof(pkh)))
json_add_string(response, "addr", out);
} else if (is_p2wsh(fallback, &wsh)) {
char out[73 + strlen(chain->bip173_name)];
json_add_string(response, "type", "P2WSH");
if (segwit_addr_encode(out, chain->bip173_name, 0,
(const u8 *)&wsh, sizeof(wsh)))
json_add_string(response, "addr", out);
}
json_add_hex_talarr(response, "hex", fallback);
json_object_end(response);
}
static struct command_result *json_decodepay(struct command *cmd, static struct command_result *json_decodepay(struct command *cmd,
const char *buffer, const char *buffer,
const jsmntok_t *obj UNNEEDED, const jsmntok_t *obj UNNEEDED,
@ -1450,89 +1413,7 @@ static struct command_result *json_decodepay(struct command *cmd,
} }
response = json_stream_success(cmd); response = json_stream_success(cmd);
json_add_string(response, "currency", b11->chain->bip173_name); json_add_bolt11(response, b11);
json_add_u64(response, "created_at", b11->timestamp);
json_add_u64(response, "expiry", b11->expiry);
json_add_node_id(response, "payee", &b11->receiver_id);
if (b11->msat)
json_add_amount_msat_compat(response, *b11->msat,
"msatoshi", "amount_msat");
if (b11->description) {
struct json_escape *esc = json_escape(NULL, b11->description);
json_add_escaped_string(response, "description", take(esc));
}
if (b11->description_hash)
json_add_sha256(response, "description_hash",
b11->description_hash);
json_add_num(response, "min_final_cltv_expiry",
b11->min_final_cltv_expiry);
if (b11->payment_secret)
json_add_secret(response, "payment_secret",
b11->payment_secret);
if (b11->features)
json_add_hex_talarr(response, "features", b11->features);
if (tal_count(b11->fallbacks)) {
json_array_start(response, "fallbacks");
for (size_t i = 0; i < tal_count(b11->fallbacks); i++)
json_add_fallback(response, NULL,
b11->fallbacks[i], b11->chain);
json_array_end(response);
}
if (tal_count(b11->routes)) {
size_t i, n;
json_array_start(response, "routes");
for (i = 0; i < tal_count(b11->routes); i++) {
json_array_start(response, NULL);
for (n = 0; n < tal_count(b11->routes[i]); n++) {
json_object_start(response, NULL);
json_add_node_id(response, "pubkey",
&b11->routes[i][n].pubkey);
json_add_short_channel_id(response,
"short_channel_id",
&b11->routes[i][n]
.short_channel_id);
json_add_u64(response, "fee_base_msat",
b11->routes[i][n].fee_base_msat);
json_add_u64(response, "fee_proportional_millionths",
b11->routes[i][n].fee_proportional_millionths);
json_add_num(response, "cltv_expiry_delta",
b11->routes[i][n]
.cltv_expiry_delta);
json_object_end(response);
}
json_array_end(response);
}
json_array_end(response);
}
if (!list_empty(&b11->extra_fields)) {
struct bolt11_field *extra;
json_array_start(response, "extra");
list_for_each(&b11->extra_fields, extra, list) {
char *data = tal_arr(cmd, char, tal_count(extra->data)+1);
size_t i;
for (i = 0; i < tal_count(extra->data); i++)
data[i] = bech32_charset[extra->data[i]];
data[i] = '\0';
json_object_start(response, NULL);
json_add_string(response, "tag",
tal_fmt(data, "%c", extra->tag));
json_add_string(response, "data", data);
tal_free(data);
json_object_end(response);
}
json_array_end(response);
}
json_add_sha256(response, "payment_hash", &b11->payment_hash);
json_add_string(response, "signature",
type_to_string(cmd, secp256k1_ecdsa_signature,
&b11->sig));
return command_success(cmd, response); return command_success(cmd, response);
} }

1
lightningd/peer_control.c

@ -1377,7 +1377,6 @@ static struct command_result *json_listpeers(struct command *cmd,
return command_success(cmd, response); return command_success(cmd, response);
} }
/* Magic marker: remove at your own peril! */
static const struct json_command listpeers_command = { static const struct json_command listpeers_command = {
"listpeers", "listpeers",
"network", "network",

9
lightningd/test/run-invoice-select-inchan.c

@ -250,6 +250,10 @@ void json_add_amount_sat_compat(struct json_stream *result UNNEEDED,
const char *msatfieldname) const char *msatfieldname)
{ fprintf(stderr, "json_add_amount_sat_compat called!\n"); abort(); } { fprintf(stderr, "json_add_amount_sat_compat called!\n"); abort(); }
/* Generated stub for json_add_bolt11 */
void json_add_bolt11(struct json_stream *response UNNEEDED,
const struct bolt11 *b11 UNNEEDED)
{ fprintf(stderr, "json_add_bolt11 called!\n"); abort(); }
/* Generated stub for json_add_log */ /* Generated stub for json_add_log */
void json_add_log(struct json_stream *result UNNEEDED, void json_add_log(struct json_stream *result UNNEEDED,
const struct log_book *lr UNNEEDED, const struct log_book *lr UNNEEDED,
@ -271,11 +275,6 @@ void json_add_node_id(struct json_stream *response UNNEEDED,
void json_add_preimage(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, void json_add_preimage(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
const struct preimage *preimage UNNEEDED) const struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "json_add_preimage called!\n"); abort(); } { fprintf(stderr, "json_add_preimage called!\n"); abort(); }
/* Generated stub for json_add_secret */
void json_add_secret(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED,
const struct secret *secret UNNEEDED)
{ fprintf(stderr, "json_add_secret called!\n"); abort(); }
/* Generated stub for json_add_sha256 */ /* Generated stub for json_add_sha256 */
void json_add_sha256(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, void json_add_sha256(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
const struct sha256 *hash UNNEEDED) const struct sha256 *hash UNNEEDED)

Loading…
Cancel
Save