|
|
@ -170,212 +170,6 @@ start_bitcoin_cli(struct lightningd_state *dstate, |
|
|
|
next_bcli(dstate); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_importaddress(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
if (!bcli->output) |
|
|
|
fatal("%s failed", bcli_args(bcli)); |
|
|
|
if (bcli->output_bytes != 0) |
|
|
|
fatal("%s unexpected output '%.*s'", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
} |
|
|
|
|
|
|
|
void bitcoind_watch_addr(struct lightningd_state *dstate, |
|
|
|
const struct ripemd160 *redeemhash) |
|
|
|
{ |
|
|
|
char *p2shaddr = p2sh_to_base58(dstate, dstate->config.testnet, |
|
|
|
redeemhash); |
|
|
|
|
|
|
|
start_bitcoin_cli(dstate, 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 *dstate, |
|
|
|
const struct sha256_double *txid, |
|
|
|
int confirmations, bool is_coinbase, |
|
|
|
const struct sha256_double *blkhash) = bcli->cb; |
|
|
|
|
|
|
|
if (!bcli->output) |
|
|
|
fatal("%s failed", bcli_args(bcli)); |
|
|
|
|
|
|
|
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid); |
|
|
|
if (!tokens) |
|
|
|
fatal("%s: %s response", |
|
|
|
bcli_args(bcli), |
|
|
|
valid ? "partial" : "invalid"); |
|
|
|
|
|
|
|
if (tokens[0].type != JSMN_ARRAY) |
|
|
|
fatal("listtransactions: %s gave non-array (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
end = json_next(tokens); |
|
|
|
for (t = tokens + 1; t < end; t = json_next(t)) { |
|
|
|
struct sha256_double txid, blkhash; |
|
|
|
const jsmntok_t *txidtok, *conftok, *blkindxtok, *blktok; |
|
|
|
unsigned int conf; |
|
|
|
bool is_coinbase; |
|
|
|
|
|
|
|
txidtok = json_get_member(bcli->output, t, "txid"); |
|
|
|
conftok = json_get_member(bcli->output, t, "confirmations"); |
|
|
|
blkindxtok = json_get_member(bcli->output, t, "blockindex"); |
|
|
|
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); |
|
|
|
} |
|
|
|
if (!json_tok_number(bcli->output, conftok, &conf)) |
|
|
|
fatal("listtransactions: bad confirmations '%.*s'", |
|
|
|
(int)(conftok->end - conftok->start), |
|
|
|
bcli->output + conftok->start); |
|
|
|
|
|
|
|
/* This can happen with zero conf. */ |
|
|
|
blkindxtok = json_get_member(bcli->output, t, "blockindex"); |
|
|
|
if (!blkindxtok) { |
|
|
|
if (conf != 0) |
|
|
|
fatal("listtransactions: no blockindex"); |
|
|
|
is_coinbase = false; |
|
|
|
} else { |
|
|
|
unsigned int blkidx; |
|
|
|
if (conf == 0) |
|
|
|
fatal("listtransactions: expect no blockindex"); |
|
|
|
if (!json_tok_number(bcli->output, blkindxtok, &blkidx)) |
|
|
|
fatal("listtransactions: bad blockindex '%.*s'", |
|
|
|
(int)(blkindxtok->end - blkindxtok->start), |
|
|
|
bcli->output + blkindxtok->start); |
|
|
|
is_coinbase = (blkidx == 0); |
|
|
|
|
|
|
|
blktok = json_get_member(bcli->output, t, "blockhash"); |
|
|
|
if (!blktok) |
|
|
|
fatal("listtransactions: no blockhash field!"); |
|
|
|
|
|
|
|
if (!bitcoin_blkid_from_hex(bcli->output + blktok->start, |
|
|
|
blktok->end - blktok->start, |
|
|
|
&blkhash)) { |
|
|
|
fatal("listtransactions: bad blockhash '%.*s'", |
|
|
|
(int)(blktok->end - blktok->start), |
|
|
|
bcli->output + blktok->start); |
|
|
|
} |
|
|
|
} |
|
|
|
/* FIXME: log txid, blkid */ |
|
|
|
log_debug(bcli->dstate->base_log, |
|
|
|
"txid %02x%02x%02x%02x..., conf %u, coinbase %u", |
|
|
|
txid.sha.u.u8[0], txid.sha.u.u8[1], |
|
|
|
txid.sha.u.u8[2], txid.sha.u.u8[3], |
|
|
|
conf, is_coinbase); |
|
|
|
|
|
|
|
cb(bcli->dstate, &txid, conf, is_coinbase, |
|
|
|
conf ? &blkhash : NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void bitcoind_poll_transactions(struct lightningd_state *dstate, |
|
|
|
void (*cb)(struct lightningd_state *dstate, |
|
|
|
const struct sha256_double *txid, |
|
|
|
int confirmations, |
|
|
|
bool is_coinbase, |
|
|
|
const struct sha256_double *blkhash)) |
|
|
|
{ |
|
|
|
/* FIXME: Iterate and detect duplicates. */ |
|
|
|
start_bitcoin_cli(dstate, process_transactions, cb, NULL, |
|
|
|
"listtransactions", "*", "100000", "0", "true", |
|
|
|
NULL); |
|
|
|
} |
|
|
|
|
|
|
|
struct txid_lookup { |
|
|
|
char txidhex[sizeof(struct sha256_double) * 2 + 1]; |
|
|
|
void *cb_arg; |
|
|
|
}; |
|
|
|
|
|
|
|
static void process_rawtx(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
struct bitcoin_tx *tx; |
|
|
|
struct txid_lookup *lookup = bcli->cb_arg; |
|
|
|
void (*cb)(struct lightningd_state *dstate, |
|
|
|
const struct bitcoin_tx *tx, void *arg) = bcli->cb; |
|
|
|
|
|
|
|
if (!bcli->output) |
|
|
|
fatal("%s: unknown txid?", bcli_args(bcli)); |
|
|
|
|
|
|
|
tx = bitcoin_tx_from_hex(bcli, bcli->output, bcli->output_bytes); |
|
|
|
if (!tx) |
|
|
|
fatal("%s: bad txid: %.*s?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, (char *)bcli->output); |
|
|
|
cb(bcli->dstate, tx, lookup->cb_arg); |
|
|
|
tal_free(lookup); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_tx(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
const jsmntok_t *tokens, *hex; |
|
|
|
bool valid; |
|
|
|
struct bitcoin_tx *tx; |
|
|
|
void (*cb)(struct lightningd_state *dstate, |
|
|
|
const struct bitcoin_tx *tx, void *arg) = bcli->cb; |
|
|
|
struct txid_lookup *lookup = bcli->cb_arg; |
|
|
|
|
|
|
|
/* Failed? Try getrawtransaction instead */ |
|
|
|
if (!bcli->output) { |
|
|
|
start_bitcoin_cli(bcli->dstate, process_rawtx, cb, lookup, |
|
|
|
"getrawtransaction", lookup->txidhex, NULL); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid); |
|
|
|
if (!tokens) |
|
|
|
fatal("%s: %s response (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
valid ? "partial" : "invalid", |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
if (tokens[0].type != JSMN_OBJECT) |
|
|
|
fatal("%s: gave non-object (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
hex = json_get_member(bcli->output, tokens, "hex"); |
|
|
|
if (!hex) |
|
|
|
fatal("%s: had no hex member (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
tx = bitcoin_tx_from_hex(bcli, bcli->output + hex->start, |
|
|
|
hex->end - hex->start); |
|
|
|
if (!tx) |
|
|
|
fatal("%s: had bad hex member (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
hex->end - hex->start, bcli->output + hex->start); |
|
|
|
cb(bcli->dstate, tx, lookup->cb_arg); |
|
|
|
tal_free(lookup); |
|
|
|
} |
|
|
|
|
|
|
|
/* FIXME: Cache! */ |
|
|
|
void bitcoind_txid_lookup_(struct lightningd_state *dstate, |
|
|
|
const struct sha256_double *txid, |
|
|
|
void (*cb)(struct lightningd_state *dstate, |
|
|
|
const struct bitcoin_tx *tx, |
|
|
|
void *arg), |
|
|
|
void *arg) |
|
|
|
{ |
|
|
|
struct txid_lookup *lookup = tal(dstate, struct txid_lookup); |
|
|
|
|
|
|
|
/* We stash this here, and place lookup into cb_arg */ |
|
|
|
lookup->cb_arg = arg; |
|
|
|
if (!bitcoin_txid_to_hex(txid, lookup->txidhex, sizeof(lookup->txidhex))) |
|
|
|
fatal("Incorrect txid size"); |
|
|
|
start_bitcoin_cli(dstate, process_tx, cb, lookup, |
|
|
|
"gettransaction", lookup->txidhex, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_estimatefee(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
double fee; |
|
|
@ -454,54 +248,6 @@ void bitcoind_send_tx(struct lightningd_state *dstate, |
|
|
|
tal_free(raw); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_getblock_for_mediantime(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
const jsmntok_t *tokens, *mediantime; |
|
|
|
bool valid; |
|
|
|
|
|
|
|
log_debug(bcli->dstate->base_log, "Got getblock result"); |
|
|
|
if (!bcli->output) |
|
|
|
fatal("%s failed", bcli_args(bcli)); |
|
|
|
|
|
|
|
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid); |
|
|
|
if (!tokens) |
|
|
|
fatal("%s: %s response", |
|
|
|
bcli_args(bcli), |
|
|
|
valid ? "partial" : "invalid"); |
|
|
|
|
|
|
|
if (tokens[0].type != JSMN_OBJECT) |
|
|
|
fatal("%s: gave non-object (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
mediantime = json_get_member(bcli->output, tokens, "mediantime"); |
|
|
|
if (!mediantime) |
|
|
|
fatal("%s: gave no mediantime field (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
if (!json_tok_number(bcli->output, mediantime, bcli->cb_arg)) |
|
|
|
fatal("%s: gave invalud mediantime (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
mediantime->end - mediantime->start, |
|
|
|
bcli->output + mediantime->start); |
|
|
|
|
|
|
|
log_debug(bcli->dstate->base_log, "mediantime = %u", |
|
|
|
*(u32 *)bcli->cb_arg); |
|
|
|
} |
|
|
|
|
|
|
|
void bitcoind_get_mediantime(struct lightningd_state *dstate, |
|
|
|
const struct sha256_double *blockid, |
|
|
|
u32 *mediantime) |
|
|
|
{ |
|
|
|
char hex[hex_str_size(sizeof(*blockid))]; |
|
|
|
|
|
|
|
bitcoin_blkid_to_hex(blockid, hex, sizeof(hex)); |
|
|
|
start_bitcoin_cli(dstate, process_getblock_for_mediantime, |
|
|
|
NULL, mediantime, |
|
|
|
"getblock", hex, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_chaintips(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
const jsmntok_t *tokens, *t, *end; |
|
|
@ -570,161 +316,6 @@ struct normalizing { |
|
|
|
void *cb_arg; |
|
|
|
}; |
|
|
|
|
|
|
|
/* We append normalized ones, so block contains both. Yuk! */ |
|
|
|
static void normalize_txids(struct lightningd_state *dstate, |
|
|
|
const struct bitcoin_tx *tx, |
|
|
|
struct normalizing *norm) |
|
|
|
{ |
|
|
|
size_t num = tal_count(norm->txids) / 2; |
|
|
|
normalized_txid(tx, &norm->txids[num + norm->i]); |
|
|
|
|
|
|
|
norm->i++; |
|
|
|
if (norm->i == num) { |
|
|
|
norm->cb(dstate, &norm->blkid, &norm->prevblk, norm->txids, |
|
|
|
norm->mediantime, norm->cb_arg); |
|
|
|
tal_free(norm); |
|
|
|
return; |
|
|
|
} |
|
|
|
bitcoind_txid_lookup(dstate, &norm->txids[norm->i], |
|
|
|
normalize_txids, norm); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_getblock(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
const jsmntok_t *tokens, *prevblk_tok, *txs_tok, |
|
|
|
*mediantime_tok, *blkid_tok, *t, *end; |
|
|
|
bool valid; |
|
|
|
u32 mediantime; |
|
|
|
struct sha256_double *txids; |
|
|
|
struct sha256_double *prevblk, blkid; |
|
|
|
size_t i; |
|
|
|
struct normalizing *norm = tal(bcli->dstate, struct normalizing); |
|
|
|
|
|
|
|
log_debug(bcli->dstate->base_log, "Got getblock result"); |
|
|
|
if (!bcli->output) |
|
|
|
fatal("%s failed", bcli_args(bcli)); |
|
|
|
|
|
|
|
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid); |
|
|
|
if (!tokens) |
|
|
|
fatal("%s: %s response", |
|
|
|
bcli_args(bcli), |
|
|
|
valid ? "partial" : "invalid"); |
|
|
|
|
|
|
|
if (tokens[0].type != JSMN_OBJECT) |
|
|
|
fatal("%s: gave non-object (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
mediantime_tok = json_get_member(bcli->output, tokens, "mediantime"); |
|
|
|
if (!mediantime_tok) |
|
|
|
fatal("%s: gave no mediantime field (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
if (!json_tok_number(bcli->output, mediantime_tok, &mediantime)) |
|
|
|
fatal("%s: gave invalid mediantime (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
mediantime_tok->end - mediantime_tok->start, |
|
|
|
bcli->output + mediantime_tok->start); |
|
|
|
|
|
|
|
/* Genesis block doesn't have this! */ |
|
|
|
prevblk_tok = json_get_member(bcli->output, tokens, "previousblockhash"); |
|
|
|
if (prevblk_tok) { |
|
|
|
prevblk = tal(bcli, struct sha256_double); |
|
|
|
if (!bitcoin_blkid_from_hex(bcli->output + prevblk_tok->start, |
|
|
|
prevblk_tok->end - prevblk_tok->start, |
|
|
|
prevblk)) { |
|
|
|
fatal("%s: bad previousblockhash '%.*s'", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)(prevblk_tok->end - prevblk_tok->start), |
|
|
|
bcli->output + prevblk_tok->start); |
|
|
|
} |
|
|
|
} else |
|
|
|
prevblk = NULL; |
|
|
|
|
|
|
|
blkid_tok = json_get_member(bcli->output, tokens, "hash"); |
|
|
|
if (!blkid_tok) |
|
|
|
fatal("%s: gave no hash field (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
if (!bitcoin_blkid_from_hex(bcli->output + blkid_tok->start, |
|
|
|
blkid_tok->end - blkid_tok->start, |
|
|
|
&blkid)) { |
|
|
|
fatal("%s: bad hash '%.*s'", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)(blkid_tok->end - blkid_tok->start), |
|
|
|
bcli->output + blkid_tok->start); |
|
|
|
} |
|
|
|
|
|
|
|
txs_tok = json_get_member(bcli->output, tokens, "tx"); |
|
|
|
if (!txs_tok) |
|
|
|
fatal("%s: gave no tx field (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
if (txs_tok->type != JSMN_ARRAY) |
|
|
|
fatal("%s: gave non-array txs field (%.*s)?", |
|
|
|
bcli_args(bcli), |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
/* It's a flat array of strings, so we can just use tok->size here. */ |
|
|
|
txids = tal_arr(bcli, struct sha256_double, txs_tok->size); |
|
|
|
end = json_next(txs_tok); |
|
|
|
for (i = 0, t = txs_tok + 1; t < end; t = json_next(t), i++) { |
|
|
|
assert(i < txs_tok->size); |
|
|
|
if (!bitcoin_txid_from_hex(bcli->output + t->start, |
|
|
|
t->end - t->start, |
|
|
|
&txids[i])) |
|
|
|
fatal("%s: gave bad txid for %zu'th tx (%.*s)?", |
|
|
|
bcli_args(bcli), i, |
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
} |
|
|
|
/* We must have coinbase, at least! */ |
|
|
|
if (i == 0) |
|
|
|
fatal("%s: gave empty txids array (%.*s)?", |
|
|
|
bcli_args(bcli), (int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
|
|
log_debug(bcli->dstate->base_log, |
|
|
|
"%.*s: mediantime = %u, prevhash=%.*s, %zu txids", |
|
|
|
(int)(blkid_tok->end - blkid_tok->start), |
|
|
|
bcli->output + blkid_tok->start, |
|
|
|
mediantime, |
|
|
|
prevblk_tok ? (int)(prevblk_tok->end - prevblk_tok->start) : 0, |
|
|
|
prevblk_tok ? bcli->output + prevblk_tok->start : NULL, |
|
|
|
i); |
|
|
|
|
|
|
|
/* FIXME: After segwitness, all txids will be "normalized" */ |
|
|
|
norm->i = 0; |
|
|
|
norm->blkid = blkid; |
|
|
|
norm->prevblk = *prevblk; |
|
|
|
norm->txids = tal_dup_arr(norm, struct sha256_double, txids, |
|
|
|
tal_count(txids), tal_count(txids)); |
|
|
|
norm->mediantime = mediantime; |
|
|
|
norm->cb = bcli->cb; |
|
|
|
norm->cb_arg = bcli->cb_arg; |
|
|
|
|
|
|
|
bitcoind_txid_lookup(bcli->dstate, &norm->txids[0], |
|
|
|
normalize_txids, norm); |
|
|
|
} |
|
|
|
|
|
|
|
void bitcoind_getblock_(struct lightningd_state *dstate, |
|
|
|
const struct sha256_double *blockid, |
|
|
|
void (*cb)(struct lightningd_state *dstate, |
|
|
|
struct sha256_double *blkid, |
|
|
|
struct sha256_double *prevblock, |
|
|
|
struct sha256_double *txids, |
|
|
|
u32 mediantime, |
|
|
|
void *arg), |
|
|
|
void *arg) |
|
|
|
{ |
|
|
|
char hex[hex_str_size(sizeof(*blockid))]; |
|
|
|
|
|
|
|
bitcoin_blkid_to_hex(blockid, hex, sizeof(hex)); |
|
|
|
start_bitcoin_cli(dstate, process_getblock, cb, arg, |
|
|
|
"getblock", hex, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
static void process_rawblock(struct bitcoin_cli *bcli) |
|
|
|
{ |
|
|
|
struct bitcoin_block *blk; |
|
|
|