mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-06 07:34:21 +01:00
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:
committed by
Christian Decker
parent
78d0a5e840
commit
45f5bb7fac
@@ -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 \
|
||||
|
||||
1194
lightningd/bolt11.c
1194
lightningd/bolt11.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user