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>
This commit is contained in:
Rusty Russell
2017-11-22 10:55:39 +10:30
committed by Christian Decker
parent 78d0a5e840
commit 45f5bb7fac
7 changed files with 210 additions and 173 deletions

View File

@@ -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 \

File diff suppressed because it is too large Load Diff

View File

@@ -1,96 +0,0 @@
#ifndef LIGHTNING_LIGHTNINGD_BOLT11_H
#define LIGHTNING_LIGHTNINGD_BOLT11_H
#include "config.h"
#include <bitcoin/pubkey.h>
#include <bitcoin/short_channel_id.h>
#include <ccan/list/list.h>
#include <ccan/short_types/short_types.h>
#include <common/hash_u5.h>
struct lightningd;
/* We only have 10 bits for the field length, meaning < 640 bytes */
#define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8)
struct bolt11_field {
struct list_node list;
char tag;
u5 *data;
};
/* BOLT #11:
* * `pubkey` (264 bits)
* * `short_channel_id` (64 bits)
* * `fee` (64 bits, big-endian)
* * `cltv_expiry_delta` (16 bits, big-endian)
*/
struct route_info {
struct pubkey pubkey;
struct short_channel_id short_channel_id;
u64 fee;
u16 cltv_expiry_delta;
};
struct bolt11 {
const struct chainparams *chain;
u64 timestamp;
u64 *msatoshi; /* NULL if not specified. */
struct sha256 payment_hash;
struct pubkey receiver_id;
/* description_hash valid iff description is NULL. */
const char *description;
struct sha256 *description_hash;
/* How many seconds to pay from @timestamp above. */
u64 expiry;
/* How many blocks final hop requires. */
u32 min_final_cltv_expiry;
/* If non-NULL, indicates a fallback address to pay to. */
const u8 *fallback;
/* If non-NULL: array of route arrays */
struct route_info **routes;
/* signature of sha256 of entire thing. */
secp256k1_ecdsa_signature sig;
struct list_head extra_fields;
};
/* Decodes and checks signature; returns NULL on error; description is
* (optional) out-of-band description of payment, for `h` field. */
struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
const char *description, char **fail);
/* Initialize an empty bolt11 struct with optional amount */
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);
/**
* bolt11_out_check - check a bolt11 struct for validity and consistency
* @bolt11: the bolt11
* @abortstr: the location to print on aborting, or NULL.
*
* Note this does not apply to bolt11's we decoded, which may not be spec
* compliant.
*
* If @abortstr is non-NULL, that will be printed in a diagnostic if the bolt11
* is invalid, and the function will abort.
*
* Returns @bolt11 if all OK, NULL if not (it can never return NULL if
* @abortstr is set).
*/
struct bolt11 *bolt11_out_check(const struct bolt11 *bolt11,
const char *abortstr);
#endif /* LIGHTNING_LIGHTNINGD_BOLT11_H */

View File

@@ -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>

View File

@@ -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);

View File

@@ -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>