From 84dc943cf513b14e3c4b2344b2e8972f3e62f0f8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 8 Jan 2021 05:17:47 +1030 Subject: [PATCH] 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 --- bitcoin/signature.c | 5 +- bitcoin/signature.h | 1 + common/Makefile | 1 + common/bolt11.c | 3 +- common/bolt11_json.c | 129 ++++++++++++++++++++ common/bolt11_json.h | 10 ++ common/test/run-bolt11.c | 4 - lightningd/Makefile | 1 + lightningd/invoice.c | 123 +------------------ lightningd/peer_control.c | 1 - lightningd/test/run-invoice-select-inchan.c | 9 +- 11 files changed, 151 insertions(+), 136 deletions(-) create mode 100644 common/bolt11_json.c create mode 100644 common/bolt11_json.h diff --git a/bitcoin/signature.c b/bitcoin/signature.c index 1c4ff47b0..afa7aeb7b 100644 --- a/bitcoin/signature.c +++ b/bitcoin/signature.c @@ -310,8 +310,7 @@ bool signature_from_der(const u8 *der, size_t len, struct bitcoin_signature *sig return true; } -static char *signature_to_hexstr(const tal_t *ctx, - const secp256k1_ecdsa_signature *sig) +char *fmt_signature(const tal_t *ctx, const secp256k1_ecdsa_signature *sig) { u8 der[72]; size_t len = 72; @@ -321,7 +320,7 @@ static char *signature_to_hexstr(const tal_t *ctx, 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, const struct bitcoin_signature *sig) diff --git a/bitcoin/signature.h b/bitcoin/signature.h index ea7a63fb1..c70bdfbc3 100644 --- a/bitcoin/signature.h +++ b/bitcoin/signature.h @@ -142,6 +142,7 @@ void fromwire_bip340sig(const u8 **cursor, size_t *max, struct bip340sig *bip340sig); /* 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); /* For caller convenience, we hand in tag in parts (any can be "") */ diff --git a/common/Makefile b/common/Makefile index 71dc75e91..92a347f82 100644 --- a/common/Makefile +++ b/common/Makefile @@ -9,6 +9,7 @@ COMMON_SRC_NOGEN := \ common/bip32.c \ common/blinding.c \ common/bolt11.c \ + common/bolt11_json.c \ common/bolt12.c \ common/channel_config.c \ common/channel_id.c \ diff --git a/common/bolt11.c b/common/bolt11.c index f91801607..8b0a014e0 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -297,8 +297,7 @@ static char *decode_n(struct bolt11 *b11, data_length * 5, false); if (!node_id_valid(&b11->receiver_id)) return tal_fmt(b11, "n: invalid pubkey %s", - type_to_string(tmpctx, struct node_id, - &b11->receiver_id)); + node_id_to_hexstr(tmpctx, &b11->receiver_id)); *have_n = true; return NULL; diff --git a/common/bolt11_json.c b/common/bolt11_json.c new file mode 100644 index 000000000..6c75de73f --- /dev/null +++ b/common/bolt11_json.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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)); +} diff --git a/common/bolt11_json.h b/common/bolt11_json.h new file mode 100644 index 000000000..fbf719983 --- /dev/null +++ b/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 */ diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index 3ce8aa16b..39747180f 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -16,10 +16,6 @@ #include /* 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 */ static struct privkey privkey; diff --git a/lightningd/Makefile b/lightningd/Makefile index f9b176996..63778b826 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -76,6 +76,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/bip32.o \ common/blinding.o \ common/bolt11.o \ + common/bolt11_json.o \ common/channel_id.o \ common/channel_config.o \ common/coin_mvt.o \ diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 848a2699b..ff66cb482 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -1,7 +1,4 @@ #include "invoice.h" -#include -#include -#include #include #include #include @@ -10,6 +7,7 @@ #include #include #include +#include #if EXPERIMENTAL_FEATURES #include #include @@ -1391,41 +1389,6 @@ static const struct 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, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -1450,89 +1413,7 @@ static struct command_result *json_decodepay(struct command *cmd, } response = json_stream_success(cmd); - 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) { - 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)); + json_add_bolt11(response, b11); return command_success(cmd, response); } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 525d0c8b3..9394e2a3a 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1377,7 +1377,6 @@ static struct command_result *json_listpeers(struct command *cmd, return command_success(cmd, response); } -/* Magic marker: remove at your own peril! */ static const struct json_command listpeers_command = { "listpeers", "network", diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index bbfe00597..ec5256a58 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/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) { 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 */ void json_add_log(struct json_stream *result 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, const struct preimage *preimage UNNEEDED) { 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 */ void json_add_sha256(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED, const struct sha256 *hash UNNEEDED)