Browse Source

bitcoind: getchaintips support.

This allows us to sae the block topology in detail.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
01e46d154e
  1. 253
      daemon/bitcoind.c
  2. 64
      daemon/bitcoind.h

253
daemon/bitcoind.c

@ -453,7 +453,7 @@ void bitcoind_send_tx(struct lightningd_state *dstate,
tal_free(raw);
}
static void process_getblock(struct bitcoin_cli *bcli)
static void process_getblock_for_mediantime(struct bitcoin_cli *bcli)
{
const jsmntok_t *tokens, *mediantime;
bool valid;
@ -496,10 +496,259 @@ void bitcoind_get_mediantime(struct lightningd_state *dstate,
char hex[hex_str_size(sizeof(*blockid))];
hex_encode(blockid, sizeof(*blockid), hex, sizeof(hex));
start_bitcoin_cli(dstate, process_getblock, NULL, mediantime,
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;
bool valid;
size_t i;
struct sha256_double *tips;
void (*cb)(struct lightningd_state *dstate,
struct sha256_double *blockids,
void *arg) = bcli->cb;
log_debug(bcli->dstate->base_log, "Got getchaintips 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_ARRAY)
fatal("%s: gave non-array (%.*s)?",
bcli_args(bcli),
(int)bcli->output_bytes, bcli->output);
tips = tal_arr(bcli, struct sha256_double, 0);
end = json_next(tokens);
for (i = 0, t = tokens + 1; t < end; t = json_next(t), i++) {
const jsmntok_t *hash = json_get_member(bcli->output, t, "hash");
tal_resize(&tips, i+1);
if (!hex_decode(bcli->output + hash->start,
hash->end - hash->start,
&tips[i], sizeof(tips[i])))
fatal("%s: gave bad hash for %zu'th tip (%.*s)?",
bcli_args(bcli), i,
(int)bcli->output_bytes, bcli->output);
}
if (i == 0)
fatal("%s: gave empty array (%.*s)?",
bcli_args(bcli), (int)bcli->output_bytes, bcli->output);
cb(bcli->dstate, tips, bcli->cb_arg);
}
void bitcoind_get_chaintips_(struct lightningd_state *dstate,
void (*cb)(struct lightningd_state *dstate,
struct sha256_double *blockids,
void *arg),
void *arg)
{
start_bitcoin_cli(dstate, process_chaintips, cb, arg,
"getchaintips", NULL);
}
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;
void (*cb)(struct lightningd_state *dstate,
struct sha256_double *blkid,
struct sha256_double *prevblock,
struct sha256_double *txids,
u32 mediantime,
void *arg) = bcli->cb;
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 (!hex_decode(bcli->output + prevblk_tok->start,
prevblk_tok->end - prevblk_tok->start,
prevblk, sizeof(*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 (!hex_decode(bcli->output + blkid_tok->start,
blkid_tok->end - blkid_tok->start,
&blkid, sizeof(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);
cb(bcli->dstate, &blkid, prevblk, txids, mediantime, bcli->cb_arg);
}
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))];
hex_encode(blockid, sizeof(*blockid), hex, sizeof(hex));
start_bitcoin_cli(dstate, process_getblock, cb, arg,
"getblock", hex, NULL);
}
static void process_getblockcount(struct bitcoin_cli *bcli)
{
u32 blockcount;
char *p, *end;
void (*cb)(struct lightningd_state *dstate,
u32 blockcount,
void *arg) = bcli->cb;
if (!bcli->output)
fatal("%s: failed", bcli_args(bcli));
p = tal_strndup(bcli, bcli->output, bcli->output_bytes);
blockcount = strtol(p, &end, 10);
if (end == p || *end != '\n')
fatal("%s: gave non-numeric blockcount %s",
bcli_args(bcli), p);
cb(bcli->dstate, blockcount, bcli->cb_arg);
}
void bitcoind_getblockcount_(struct lightningd_state *dstate,
void (*cb)(struct lightningd_state *dstate,
u32 blockcount,
void *arg),
void *arg)
{
start_bitcoin_cli(dstate, process_getblockcount, cb, arg,
"getblockcount", NULL);
}
static void process_getblockhash(struct bitcoin_cli *bcli)
{
struct sha256_double blkid;
void (*cb)(struct lightningd_state *dstate,
const struct sha256_double *blkid,
void *arg) = bcli->cb;
if (!bcli->output)
fatal("%s: failed", bcli_args(bcli));
if (bcli->output_bytes == 0
|| !hex_decode(bcli->output, bcli->output_bytes-1,
&blkid, sizeof(blkid))) {
fatal("%s: bad blockid '%.*s'",
bcli_args(bcli), (int)bcli->output_bytes, bcli->output);
}
cb(bcli->dstate, &blkid, bcli->cb_arg);
}
void bitcoind_getblockhash_(struct lightningd_state *dstate,
u32 height,
void (*cb)(struct lightningd_state *dstate,
const struct sha256_double *blkid,
void *arg),
void *arg)
{
char str[STR_MAX_CHARS(height)];
sprintf(str, "%u", height);
start_bitcoin_cli(dstate, process_getblockhash, cb, arg,
"getblockhash", str, NULL);
}
/* Make testnet/regtest status matches us. */
void check_bitcoind_config(struct lightningd_state *dstate)
{

64
daemon/bitcoind.h

@ -57,5 +57,69 @@ void bitcoind_get_mediantime(struct lightningd_state *dstate,
const struct sha256_double *blockid,
u32 *mediantime);
void bitcoind_get_chaintips_(struct lightningd_state *dstate,
void (*cb)(struct lightningd_state *dstate,
struct sha256_double *blockids,
void *arg),
void *arg);
#define bitcoind_get_chaintips(dstate, cb, arg) \
bitcoind_get_chaintips_((dstate), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct lightningd_state *, \
struct sha256_double *), \
(arg))
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);
#define bitcoind_getblock(dstate, blockid, cb, arg) \
bitcoind_getblock_((dstate), (blockid), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct lightningd_state *, \
struct sha256_double *, \
struct sha256_double *, \
struct sha256_double *, \
u32 mediantime), \
(arg))
void bitcoind_getblockcount_(struct lightningd_state *dstate,
void (*cb)(struct lightningd_state *dstate,
u32 blockcount,
void *arg),
void *arg);
#define bitcoind_getblockcount(dstate, cb, arg) \
bitcoind_getblockcount_((dstate), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct lightningd_state *, \
u32 blockcount), \
(arg))
void bitcoind_getblockhash_(struct lightningd_state *dstate,
u32 height,
void (*cb)(struct lightningd_state *dstate,
const struct sha256_double *blkid,
void *arg),
void *arg);
#define bitcoind_getblockhash(dstate, height, cb, arg) \
bitcoind_getblockhash_((dstate), \
(height), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct lightningd_state *, \
const struct sha256_double *), \
(arg))
void check_bitcoind_config(struct lightningd_state *dstate);
#endif /* LIGHTNING_DAEMON_BITCOIND_H */

Loading…
Cancel
Save