Skip to content

Commit

Permalink
common/bolt11_json: extract bolt11->json code.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
rustyrussell committed Jan 9, 2021
1 parent 1aa7e8e commit 84dc943
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 136 deletions.
5 changes: 2 additions & 3 deletions bitcoin/signature.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions bitcoin/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 "") */
Expand Down
1 change: 1 addition & 0 deletions common/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
3 changes: 1 addition & 2 deletions common/bolt11.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
129 changes: 129 additions & 0 deletions common/bolt11_json.c
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions common/bolt11_json.h
Original file line number Diff line number Diff line change
@@ -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 changes: 0 additions & 4 deletions common/test/run-bolt11.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
#include <wally_core.h>

/* 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;
Expand Down
1 change: 1 addition & 0 deletions lightningd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
123 changes: 2 additions & 121 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
#include "invoice.h"
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
#include <ccan/json_escape/json_escape.h>
Expand All @@ -10,6 +7,7 @@
#include <common/amount.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/bolt11_json.h>
#if EXPERIMENTAL_FEATURES
#include <common/bolt12.h>
#include <common/bolt12_merkle.h>
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}

Expand Down
1 change: 0 additions & 1 deletion lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
9 changes: 4 additions & 5 deletions lightningd/test/run-invoice-select-inchan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand Down

0 comments on commit 84dc943

Please sign in to comment.