Browse Source

bolt11: move to common/ and sign via callback.

JSON stuff is moved to lightningd/invoice.c.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
45f5bb7fac
  1. 1
      common/Makefile
  2. 173
      common/bolt11.c
  3. 25
      common/bolt11.h
  4. 2
      lightningd/Makefile
  5. 1
      lightningd/hsm_control.c
  6. 179
      lightningd/invoice.c
  7. 2
      lightningd/pay.c

1
common/Makefile

@ -1,6 +1,7 @@
COMMON_SRC := \
common/bech32.c \
common/bip32.c \
common/bolt11.c \
common/channel_config.c \
common/close_tx.c \
common/configdir.c \

173
lightningd/bolt11.c → common/bolt11.c

@ -8,11 +8,11 @@
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/utils.h>
#include <errno.h>
#include <hsmd/gen_hsm_wire.h>
#include <inttypes.h>
#include <lightningd/bolt11.h>
#include <lightningd/hsm_control.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
@ -877,9 +877,13 @@ static void encode_extra(u5 **data, const struct bolt11_field *extra)
}
/* Encodes, even if it's nonsense. */
char *bolt11_encode(const tal_t *ctx,
struct lightningd *ld,
const struct bolt11 *b11, bool n_field)
char *bolt11_encode_(const tal_t *ctx,
const struct bolt11 *b11, bool n_field,
bool (*sign)(const u5 *u5bytes,
const u8 *hrpu8,
secp256k1_ecdsa_recoverable_signature *rsig,
void *arg),
void *arg)
{
tal_t *tmpctx = tal_tmpctx(ctx);
u5 *data = tal_arr(tmpctx, u5, 0);
@ -889,7 +893,7 @@ char *bolt11_encode(const tal_t *ctx,
struct bolt11_field *extra;
secp256k1_ecdsa_recoverable_signature rsig;
u8 sig_and_recid[65];
u8 *hrpu8, *msg;
u8 *hrpu8;
int recid;
size_t i;
@ -963,15 +967,8 @@ char *bolt11_encode(const tal_t *ctx,
/* Need exact length here */
hrpu8 = tal_dup_arr(tmpctx, u8, (const u8 *)hrp, strlen(hrp), 0);
msg = towire_hsmctl_sign_invoice(tmpctx, data, hrpu8);
if (!wire_sync_write(ld->hsm_fd, take(msg)))
fatal("Could not write to HSM: %s", strerror(errno));
msg = hsm_sync_read(tmpctx, ld);
if (!fromwire_hsmctl_sign_invoice_reply(msg, NULL, &rsig))
fatal("HSM gave bad sign_invoice_reply %s",
tal_hex(msg, msg));
if (!sign(data, hrpu8, &rsig, arg))
return tal_free(tmpctx);
secp256k1_ecdsa_recoverable_signature_serialize_compact(
secp256k1_ctx,
@ -1044,151 +1041,3 @@ struct bolt11 *bolt11_out_check(const struct bolt11 *b11, const char *abortstr)
}
return cast_const(struct bolt11 *, b11);
}
static void json_decodepay(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *bolt11tok, *desctok;
struct bolt11 *b11;
struct json_result *response;
char *str, *desc, *fail;
if (!json_get_params(buffer, params,
"bolt11", &bolt11tok,
"?description", &desctok,
NULL)) {
command_fail(cmd, "Need bolt11 string");
return;
}
str = tal_strndup(cmd, buffer + bolt11tok->start,
bolt11tok->end - bolt11tok->start);
if (desctok)
desc = tal_strndup(cmd, buffer + desctok->start,
desctok->end - desctok->start);
else
desc = NULL;
b11 = bolt11_decode(cmd, str, desc, &fail);
if (!b11) {
command_fail(cmd, "Invalid bolt11: %s", fail);
return;
}
response = new_json_result(cmd);
json_object_start(response, NULL);
json_add_string(response, "currency", b11->chain->bip173_name);
json_add_u64(response, "timestamp", b11->timestamp);
json_add_u64(response, "expiry", b11->expiry);
json_add_pubkey(response, "payee", &b11->receiver_id);
if (b11->msatoshi)
json_add_u64(response, "msatoshi", *b11->msatoshi);
if (b11->description)
json_add_string(response, "description", b11->description);
if (b11->description_hash)
json_add_hex(response, "description_hash",
b11->description_hash,
sizeof(*b11->description_hash));
if (tal_len(b11->fallback)) {
struct bitcoin_address pkh;
struct ripemd160 sh;
struct sha256 wsh;
json_object_start(response, "fallback");
if (is_p2pkh(b11->fallback, &pkh)) {
json_add_string(response, "type", "P2PKH");
json_add_string(response, "addr",
bitcoin_to_base58(cmd,
b11->chain->testnet,
&pkh));
} else if (is_p2sh(b11->fallback, &sh)) {
json_add_string(response, "type", "P2SH");
json_add_string(response, "addr",
p2sh_to_base58(cmd,
b11->chain->testnet,
&sh));
} else if (is_p2wpkh(b11->fallback, &pkh)) {
char out[73 + strlen(b11->chain->bip173_name)];
json_add_string(response, "type", "P2WPKH");
if (segwit_addr_encode(out, b11->chain->bip173_name, 0,
(const u8 *)&pkh, sizeof(pkh)))
json_add_string(response, "addr", out);
} else if (is_p2wsh(b11->fallback, &wsh)) {
char out[73 + strlen(b11->chain->bip173_name)];
json_add_string(response, "type", "P2WSH");
if (segwit_addr_encode(out, b11->chain->bip173_name, 0,
(const u8 *)&wsh, sizeof(wsh)))
json_add_string(response, "addr", out);
}
json_add_hex(response, "hex",
b11->fallback, tal_len(b11->fallback));
json_object_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_pubkey(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",
b11->routes[i][n].fee);
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_len(extra->data)+1);
size_t i;
for (i = 0; i < tal_len(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_hex(response, "payment_hash",
&b11->payment_hash, sizeof(b11->payment_hash));
json_add_string(response, "signature",
type_to_string(cmd, secp256k1_ecdsa_signature,
&b11->sig));
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command decodepay_command = {
"decodepay",
json_decodepay,
"Parse and decode {bolt11} if possible",
"Returns a verbose description on success"
};
AUTODATA(json_command, &decodepay_command);

25
lightningd/bolt11.h → common/bolt11.h

@ -1,5 +1,5 @@
#ifndef LIGHTNING_LIGHTNINGD_BOLT11_H
#define LIGHTNING_LIGHTNINGD_BOLT11_H
#ifndef LIGHTNING_COMMON_BOLT11_H
#define LIGHTNING_COMMON_BOLT11_H
#include "config.h"
#include <bitcoin/pubkey.h>
@ -7,8 +7,7 @@
#include <ccan/list/list.h>
#include <ccan/short_types/short_types.h>
#include <common/hash_u5.h>
struct lightningd;
#include <secp256k1_recovery.h>
/* We only have 10 bits for the field length, meaning < 640 bytes */
#define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8)
@ -73,9 +72,21 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
struct bolt11 *new_bolt11(const tal_t *ctx, u64 *msatoshi);
/* Encodes and signs, even if it's nonsense. */
char *bolt11_encode(const tal_t *ctx,
struct lightningd *ld,
const struct bolt11 *b11, bool n_field);
char *bolt11_encode_(const tal_t *ctx,
const struct bolt11 *b11, bool n_field,
bool (*sign)(const u5 *u5bytes,
const u8 *hrpu8,
secp256k1_ecdsa_recoverable_signature *rsig,
void *arg),
void *arg);
#define bolt11_encode(ctx, b11, n_field, sign, arg) \
bolt11_encode_((ctx), (b11), (n_field), \
typesafe_cb_preargs(bool, void *, (sign), (arg), \
const u5 *, \
const u8 *, \
secp256k1_ecdsa_recoverable_signature *rsig), \
(arg))
/**
* bolt11_out_check - check a bolt11 struct for validity and consistency

2
lightningd/Makefile

@ -16,6 +16,7 @@ default: lightningd-all
LIGHTNINGD_COMMON_OBJS := \
common/bech32.o \
common/bip32.o \
common/bolt11.o \
common/channel_config.o \
common/configdir.o \
common/crypto_state.o \
@ -42,7 +43,6 @@ LIGHTNINGD_COMMON_OBJS := \
LIGHTNINGD_SRC := \
lightningd/bitcoind.c \
lightningd/bolt11.c \
lightningd/build_utxos.c \
lightningd/chaintopology.c \
lightningd/gossip_control.c \

1
lightningd/hsm_control.c

@ -9,6 +9,7 @@
#include <errno.h>
#include <hsmd/gen_hsm_wire.h>
#include <inttypes.h>
#include <lightningd/hsm_control.h>
#include <lightningd/log.h>
#include <string.h>
#include <wally_bip32.h>

179
lightningd/invoice.c

@ -1,14 +1,22 @@
#include "invoice.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/script.h>
#include <ccan/str/hex/hex.h>
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/utils.h>
#include <errno.h>
#include <hsmd/gen_hsm_wire.h>
#include <inttypes.h>
#include <lightningd/bolt11.h>
#include <lightningd/hsm_control.h>
#include <lightningd/log.h>
#include <sodium/randombytes.h>
#include <wire/wire_sync.h>
struct invoice_waiter {
struct list_node list;
@ -100,6 +108,25 @@ void resolve_invoice(struct lightningd *ld, struct invoice *invoice)
wallet_payment_set_status(ld->wallet, &invoice->rhash, PAYMENT_COMPLETE);
}
static bool hsm_sign_b11(const u5 *u5bytes,
const u8 *hrpu8,
secp256k1_ecdsa_recoverable_signature *rsig,
struct lightningd *ld)
{
u8 *msg = towire_hsmctl_sign_invoice(ld, u5bytes, hrpu8);
if (!wire_sync_write(ld->hsm_fd, take(msg)))
fatal("Could not write to HSM: %s", strerror(errno));
msg = hsm_sync_read(ld, ld);
if (!fromwire_hsmctl_sign_invoice_reply(msg, NULL, rsig))
fatal("HSM gave bad sign_invoice_reply %s",
tal_hex(msg, msg));
tal_free(msg);
return true;
}
static void json_invoice(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
@ -178,7 +205,7 @@ static void json_invoice(struct command *cmd,
desc->end - desc->start);
/* FIXME: add private routes if necessary! */
b11enc = bolt11_encode(cmd, cmd->ld, b11, false);
b11enc = bolt11_encode(cmd, b11, false, hsm_sign_b11, cmd->ld);
/* OK, connect it to main state, respond with hash */
tal_steal(invs, invoice);
@ -421,3 +448,151 @@ static const struct json_command waitinvoice_command = {
"Returns {label}, {rhash} and {msatoshi} on success"
};
AUTODATA(json_command, &waitinvoice_command);
static void json_decodepay(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *bolt11tok, *desctok;
struct bolt11 *b11;
struct json_result *response;
char *str, *desc, *fail;
if (!json_get_params(buffer, params,
"bolt11", &bolt11tok,
"?description", &desctok,
NULL)) {
command_fail(cmd, "Need bolt11 string");
return;
}
str = tal_strndup(cmd, buffer + bolt11tok->start,
bolt11tok->end - bolt11tok->start);
if (desctok)
desc = tal_strndup(cmd, buffer + desctok->start,
desctok->end - desctok->start);
else
desc = NULL;
b11 = bolt11_decode(cmd, str, desc, &fail);
if (!b11) {
command_fail(cmd, "Invalid bolt11: %s", fail);
return;
}
response = new_json_result(cmd);
json_object_start(response, NULL);
json_add_string(response, "currency", b11->chain->bip173_name);
json_add_u64(response, "timestamp", b11->timestamp);
json_add_u64(response, "expiry", b11->expiry);
json_add_pubkey(response, "payee", &b11->receiver_id);
if (b11->msatoshi)
json_add_u64(response, "msatoshi", *b11->msatoshi);
if (b11->description)
json_add_string(response, "description", b11->description);
if (b11->description_hash)
json_add_hex(response, "description_hash",
b11->description_hash,
sizeof(*b11->description_hash));
if (tal_len(b11->fallback)) {
struct bitcoin_address pkh;
struct ripemd160 sh;
struct sha256 wsh;
json_object_start(response, "fallback");
if (is_p2pkh(b11->fallback, &pkh)) {
json_add_string(response, "type", "P2PKH");
json_add_string(response, "addr",
bitcoin_to_base58(cmd,
b11->chain->testnet,
&pkh));
} else if (is_p2sh(b11->fallback, &sh)) {
json_add_string(response, "type", "P2SH");
json_add_string(response, "addr",
p2sh_to_base58(cmd,
b11->chain->testnet,
&sh));
} else if (is_p2wpkh(b11->fallback, &pkh)) {
char out[73 + strlen(b11->chain->bip173_name)];
json_add_string(response, "type", "P2WPKH");
if (segwit_addr_encode(out, b11->chain->bip173_name, 0,
(const u8 *)&pkh, sizeof(pkh)))
json_add_string(response, "addr", out);
} else if (is_p2wsh(b11->fallback, &wsh)) {
char out[73 + strlen(b11->chain->bip173_name)];
json_add_string(response, "type", "P2WSH");
if (segwit_addr_encode(out, b11->chain->bip173_name, 0,
(const u8 *)&wsh, sizeof(wsh)))
json_add_string(response, "addr", out);
}
json_add_hex(response, "hex",
b11->fallback, tal_len(b11->fallback));
json_object_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_pubkey(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",
b11->routes[i][n].fee);
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_len(extra->data)+1);
size_t i;
for (i = 0; i < tal_len(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_hex(response, "payment_hash",
&b11->payment_hash, sizeof(b11->payment_hash));
json_add_string(response, "signature",
type_to_string(cmd, secp256k1_ecdsa_signature,
&b11->sig));
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command decodepay_command = {
"decodepay",
json_decodepay,
"Parse and decode {bolt11} if possible",
"Returns a verbose description on success"
};
AUTODATA(json_command, &decodepay_command);

2
lightningd/pay.c

@ -4,10 +4,10 @@
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
#include <channeld/gen_channel_wire.h>
#include <common/bolt11.h>
#include <gossipd/gen_gossip_wire.h>
#include <gossipd/routing.h>
#include <inttypes.h>
#include <lightningd/bolt11.h>
#include <lightningd/chaintopology.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>

Loading…
Cancel
Save