5 changed files with 270 additions and 0 deletions
@ -0,0 +1,231 @@ |
|||
/* Code for talking to bitcoind. We use bitcoin-cli. */ |
|||
#include "bitcoin/base58.h" |
|||
#include "bitcoin/shadouble.h" |
|||
#include "bitcoin/tx.h" |
|||
#include "bitcoind.h" |
|||
#include "json.h" |
|||
#include "lightningd.h" |
|||
#include "log.h" |
|||
#include <ccan/cast/cast.h> |
|||
#include <ccan/io/io.h> |
|||
#include <ccan/pipecmd/pipecmd.h> |
|||
#include <ccan/str/hex/hex.h> |
|||
#include <ccan/tal/str/str.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <errno.h> |
|||
|
|||
#define BITCOIN_CLI "bitcoin-cli" |
|||
|
|||
static char **gather_args(const tal_t *ctx, const char *cmd, va_list ap) |
|||
{ |
|||
size_t n = 2; |
|||
char **args = tal_arr(ctx, char *, n+1); |
|||
|
|||
args[0] = BITCOIN_CLI; |
|||
args[1] = cast_const(char *, cmd); |
|||
|
|||
while ((args[n] = va_arg(ap, char *)) != NULL) { |
|||
args[n] = tal_strdup(args, args[n]); |
|||
n++; |
|||
tal_resize(&args, n + 1); |
|||
} |
|||
return args; |
|||
} |
|||
|
|||
struct bitcoin_cli { |
|||
struct lightningd_state *state; |
|||
int fd; |
|||
pid_t pid; |
|||
char **args; |
|||
char *output; |
|||
size_t output_bytes; |
|||
size_t new_output; |
|||
void (*process)(struct bitcoin_cli *); |
|||
void *cb; |
|||
void *cb_arg; |
|||
}; |
|||
|
|||
static struct io_plan *read_more(struct io_conn *conn, struct bitcoin_cli *bcli) |
|||
{ |
|||
bcli->output_bytes += bcli->new_output; |
|||
if (bcli->output_bytes == tal_count(bcli->output)) |
|||
tal_resize(&bcli->output, bcli->output_bytes * 2); |
|||
return io_read_partial(conn, bcli->output + bcli->output_bytes, |
|||
tal_count(bcli->output) - bcli->output_bytes, |
|||
&bcli->new_output, read_more, bcli); |
|||
} |
|||
|
|||
static struct io_plan *output_init(struct io_conn *conn, struct bitcoin_cli *bcli) |
|||
{ |
|||
bcli->output_bytes = bcli->new_output = 0; |
|||
bcli->output = tal_arr(bcli, char, 100); |
|||
return read_more(conn, bcli); |
|||
} |
|||
|
|||
static void bcli_finished(struct io_conn *conn, struct bitcoin_cli *bcli) |
|||
{ |
|||
int ret, status; |
|||
|
|||
/* FIXME: If we waited for SIGCHILD, this could never hang! */ |
|||
ret = waitpid(bcli->pid, &status, 0); |
|||
if (ret != bcli->pid) |
|||
fatal("bitcoind: '%s' '%s' %s", |
|||
bcli->args[0], bcli->args[1], |
|||
ret == 0 ? "not exited?" : strerror(errno)); |
|||
|
|||
if (!WIFEXITED(status)) |
|||
fatal("bitcoind: '%s' '%s' died with signal %i", |
|||
bcli->args[0], bcli->args[1], |
|||
WTERMSIG(status)); |
|||
|
|||
if (WEXITSTATUS(status) != 0) |
|||
fatal("bitcoind: '%s' '%s' failed (%i '%.*s')", |
|||
bcli->args[0], bcli->args[1], WEXITSTATUS(status), |
|||
(int)bcli->output_bytes, bcli->output); |
|||
|
|||
assert(bcli->state->bitcoind_in_progress); |
|||
bcli->state->bitcoind_in_progress--; |
|||
bcli->process(bcli); |
|||
} |
|||
|
|||
static void |
|||
start_bitcoin_cli(struct lightningd_state *state, |
|||
void (*process)(struct bitcoin_cli *), |
|||
void *cb, void *cb_arg, |
|||
char *cmd, ...) |
|||
{ |
|||
va_list ap; |
|||
struct bitcoin_cli *bcli = tal(state, struct bitcoin_cli); |
|||
struct io_conn *conn; |
|||
|
|||
bcli->state = state; |
|||
bcli->process = process; |
|||
bcli->cb = cb; |
|||
bcli->cb_arg = cb_arg; |
|||
va_start(ap, cmd); |
|||
bcli->args = gather_args(bcli, cmd, ap); |
|||
va_end(ap); |
|||
|
|||
bcli->pid = pipecmdarr(&bcli->fd, NULL, &bcli->fd, bcli->args); |
|||
if (bcli->pid < 0) |
|||
fatal("%s exec failed: %s", bcli->args[0], strerror(errno)); |
|||
|
|||
conn = io_new_conn(state, bcli->fd, output_init, bcli); |
|||
tal_steal(conn, bcli); |
|||
state->bitcoind_in_progress++; |
|||
io_set_finish(conn, bcli_finished, bcli); |
|||
} |
|||
|
|||
static void process_importaddress(struct bitcoin_cli *bcli) |
|||
{ |
|||
if (bcli->output_bytes != 0) |
|||
fatal("bitcoind: '%s' '%s' unexpeced output '%.*s'", |
|||
bcli->args[0], bcli->args[1], |
|||
(int)bcli->output_bytes, bcli->output); |
|||
} |
|||
|
|||
void bitcoind_watch_addr(struct lightningd_state *state, |
|||
const struct ripemd160 *redeemhash) |
|||
{ |
|||
char *p2shaddr = p2sh_to_base58(state, state->config.testnet, |
|||
redeemhash); |
|||
|
|||
start_bitcoin_cli(state, process_importaddress, NULL, NULL, |
|||
"importaddress", p2shaddr, "", "false", NULL); |
|||
tal_free(p2shaddr); |
|||
} |
|||
|
|||
static void process_transactions(struct bitcoin_cli *bcli) |
|||
{ |
|||
const jsmntok_t *tokens, *t, *end; |
|||
bool valid; |
|||
void (*cb)(struct lightningd_state *state, |
|||
const struct sha256_double *txid, |
|||
int confirmations) = bcli->cb; |
|||
|
|||
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid); |
|||
if (!tokens) |
|||
fatal("bitcoind: '%s' '%s' %s response", |
|||
bcli->args[0], bcli->args[1], |
|||
valid ? "partial" : "invalid"); |
|||
|
|||
if (tokens[0].type != JSMN_ARRAY) |
|||
fatal("listtransactions: '%s' '%s' gave non-array (%.*s)?", |
|||
bcli->args[0], bcli->args[1], |
|||
(int)bcli->output_bytes, bcli->output); |
|||
|
|||
end = json_next(tokens); |
|||
for (t = tokens + 1; t < end; t = json_next(t)) { |
|||
struct sha256_double txid; |
|||
const jsmntok_t *txidtok, *conftok; |
|||
long int conf; |
|||
char *end; |
|||
|
|||
txidtok = json_get_member(bcli->output, t, "txid"); |
|||
conftok = json_get_member(bcli->output, t, "confirmations"); |
|||
if (!txidtok || !conftok) |
|||
fatal("listtransactions: no %s field!", |
|||
txidtok ? "confirmations" : "txid"); |
|||
if (!bitcoin_txid_from_hex(bcli->output + txidtok->start, |
|||
txidtok->end - txidtok->start, |
|||
&txid)) { |
|||
fatal("listtransactions: bad txid '%.*s'", |
|||
(int)(txidtok->end - txidtok->start), |
|||
bcli->output + txidtok->start); |
|||
} |
|||
conf = strtol(bcli->output + conftok->start, &end, 10); |
|||
if (end != bcli->output + conftok->end) |
|||
fatal("listtransactions: bad confirmations '%.*s'", |
|||
(int)(conftok->end - conftok->start), |
|||
bcli->output + conftok->start); |
|||
|
|||
/* FIXME: log txid */ |
|||
log_debug(bcli->state->base_log, |
|||
"txid %02x%02x%02x%02x..., conf %li", |
|||
txid.sha.u.u8[0], txid.sha.u.u8[1], |
|||
txid.sha.u.u8[2], txid.sha.u.u8[3], |
|||
conf); |
|||
|
|||
cb(bcli->state, &txid, conf); |
|||
} |
|||
} |
|||
|
|||
void bitcoind_poll_transactions(struct lightningd_state *state, |
|||
void (*cb)(struct lightningd_state *state, |
|||
const struct sha256_double *txid, |
|||
int confirmations)) |
|||
{ |
|||
/* FIXME: Iterate and detect duplicates. */ |
|||
start_bitcoin_cli(state, process_transactions, cb, NULL, |
|||
"listtransactions", "*", "100000", "0", "true", |
|||
NULL); |
|||
} |
|||
|
|||
static void process_rawtx(struct bitcoin_cli *bcli) |
|||
{ |
|||
struct bitcoin_tx *tx; |
|||
void (*cb)(struct lightningd_state *state, |
|||
const struct bitcoin_tx *tx, void *arg) = bcli->cb; |
|||
|
|||
tx = bitcoin_tx_from_hex(bcli, bcli->output, bcli->output_bytes); |
|||
if (!tx) |
|||
fatal("Unknown txid (output %.*s)", |
|||
(int)bcli->output_bytes, (char *)bcli->output); |
|||
cb(bcli->state, tx, bcli->cb_arg); |
|||
} |
|||
|
|||
/* FIXME: Cache! */ |
|||
void bitcoind_txid_lookup_(struct lightningd_state *state, |
|||
const struct sha256_double *txid, |
|||
void (*cb)(struct lightningd_state *state, |
|||
const struct bitcoin_tx *tx, |
|||
void *arg), |
|||
void *arg) |
|||
{ |
|||
char txidhex[hex_str_size(sizeof(*txid))]; |
|||
|
|||
if (!bitcoin_txid_to_hex(txid, txidhex, sizeof(txidhex))) |
|||
fatal("Incorrect txid size"); |
|||
start_bitcoin_cli(state, process_rawtx, cb, arg, |
|||
"getrawtransaction", txidhex, NULL); |
|||
} |
@ -0,0 +1,33 @@ |
|||
#ifndef LIGHTNING_DAEMON_BITCOIND_H |
|||
#define LIGHTNING_DAEMON_BITCOIND_H |
|||
#include "config.h" |
|||
#include <ccan/typesafe_cb/typesafe_cb.h> |
|||
|
|||
struct sha256_double; |
|||
struct lightningd_state; |
|||
struct ripemd160; |
|||
struct bitcoin_tx; |
|||
|
|||
void bitcoind_watch_addr(struct lightningd_state *state, |
|||
const struct ripemd160 *redeemhash); |
|||
|
|||
void bitcoind_poll_transactions(struct lightningd_state *state, |
|||
void (*cb)(struct lightningd_state *state, |
|||
const struct sha256_double *txid, |
|||
int confirmations)); |
|||
|
|||
void bitcoind_txid_lookup_(struct lightningd_state *state, |
|||
const struct sha256_double *txid, |
|||
void (*cb)(struct lightningd_state *state, |
|||
const struct bitcoin_tx *tx, void *), |
|||
void *arg); |
|||
|
|||
#define bitcoind_txid_lookup(state, txid, cb, arg) \ |
|||
bitcoind_txid_lookup_((state), (txid), \ |
|||
typesafe_cb_preargs(struct io_plan *, void *, \ |
|||
(cb), (arg), \ |
|||
struct lightningd_state *, \ |
|||
const struct bitcoin_tx *), \ |
|||
(arg)) |
|||
|
|||
#endif /* LIGHTNING_DAEMON_BITCOIND_H */ |
Loading…
Reference in new issue