|
@ -312,13 +312,20 @@ start_bitcoin_cli(const tal_t *ctx, |
|
|
next_bcli(bcli->prio); |
|
|
next_bcli(bcli->prio); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct command_result *command_err_bcli_badjson(struct bitcoin_cli *bcli, |
|
|
|
|
|
const char *errmsg) |
|
|
|
|
|
{ |
|
|
|
|
|
char *err = tal_fmt(bcli, "%s: bad JSON: %s (%.*s)", |
|
|
|
|
|
bcli_args(bcli), errmsg, |
|
|
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static struct command_result *process_getutxout(struct bitcoin_cli *bcli) |
|
|
static struct command_result *process_getutxout(struct bitcoin_cli *bcli) |
|
|
{ |
|
|
{ |
|
|
const jsmntok_t *tokens, *valuetok, *scriptpubkeytok, *hextok; |
|
|
const jsmntok_t *tokens, *valuetok, *scriptpubkeytok, *hextok; |
|
|
struct json_stream *response; |
|
|
struct json_stream *response; |
|
|
bool valid; |
|
|
|
|
|
struct bitcoin_tx_output output; |
|
|
struct bitcoin_tx_output output; |
|
|
char *err; |
|
|
|
|
|
|
|
|
|
|
|
/* As of at least v0.15.1.0, bitcoind returns "success" but an empty
|
|
|
/* As of at least v0.15.1.0, bitcoind returns "success" but an empty
|
|
|
string on a spent txout. */ |
|
|
string on a spent txout. */ |
|
@ -330,59 +337,41 @@ static struct command_result *process_getutxout(struct bitcoin_cli *bcli) |
|
|
return command_finished(bcli->cmd, response); |
|
|
return command_finished(bcli->cmd, response); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
tokens = json_parse_input(bcli->output, bcli->output, |
|
|
tokens = json_parse_simple(bcli->output, bcli->output, |
|
|
bcli->output_bytes, &valid); |
|
|
bcli->output_bytes); |
|
|
if (!tokens) { |
|
|
if (!tokens) { |
|
|
err = tal_fmt(bcli, "%s: %s response", bcli_args(bcli), |
|
|
return command_err_bcli_badjson(bcli, "cannot parse"); |
|
|
valid ? "partial" : "invalid"); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (tokens[0].type != JSMN_OBJECT) { |
|
|
if (tokens[0].type != JSMN_OBJECT) { |
|
|
err = tal_fmt(bcli, "%s: gave non-object (%.*s)?", |
|
|
return command_err_bcli_badjson(bcli, "non-object"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
valuetok = json_get_member(bcli->output, tokens, "value"); |
|
|
valuetok = json_get_member(bcli->output, tokens, "value"); |
|
|
if (!valuetok) { |
|
|
if (!valuetok) { |
|
|
err = tal_fmt(bcli,"%s: had no value member (%.*s)?", |
|
|
return command_err_bcli_badjson(bcli, "no value member"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!json_to_bitcoin_amount(bcli->output, valuetok, &output.amount.satoshis)) {/* Raw: talking to bitcoind */ |
|
|
if (!json_to_bitcoin_amount(bcli->output, valuetok, &output.amount.satoshis)) {/* Raw: talking to bitcoind */ |
|
|
err = tal_fmt(bcli, "%s: had bad value (%.*s)?", |
|
|
return command_err_bcli_badjson(bcli, "bad value member"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
scriptpubkeytok = json_get_member(bcli->output, tokens, "scriptPubKey"); |
|
|
scriptpubkeytok = json_get_member(bcli->output, tokens, "scriptPubKey"); |
|
|
if (!scriptpubkeytok) { |
|
|
if (!scriptpubkeytok) { |
|
|
err = tal_fmt(bcli, "%s: had no scriptPubKey member (%.*s)?", |
|
|
return command_err_bcli_badjson(bcli, "no scriptPubkey member"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
hextok = json_get_member(bcli->output, scriptpubkeytok, "hex"); |
|
|
hextok = json_get_member(bcli->output, scriptpubkeytok, "hex"); |
|
|
if (!hextok) { |
|
|
if (!hextok) { |
|
|
err = tal_fmt(bcli, "%s: had no scriptPubKey->hex member (%.*s)?", |
|
|
return command_err_bcli_badjson(bcli, |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
"no scriptPubkey.hex member"); |
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
output.script = tal_hexdata(bcli, bcli->output + hextok->start, |
|
|
output.script = tal_hexdata(bcli, bcli->output + hextok->start, |
|
|
hextok->end - hextok->start); |
|
|
hextok->end - hextok->start); |
|
|
if (!output.script) { |
|
|
if (!output.script) { |
|
|
err = tal_fmt(bcli, "%s: scriptPubKey->hex invalid hex (%.*s)?", |
|
|
return command_err_bcli_badjson(bcli, |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
"scriptPubkey.hex invalid hex"); |
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
response = jsonrpc_stream_success(bcli->cmd); |
|
|
response = jsonrpc_stream_success(bcli->cmd); |
|
@ -396,56 +385,40 @@ static struct command_result *process_getblockchaininfo(struct bitcoin_cli *bcli |
|
|
{ |
|
|
{ |
|
|
const jsmntok_t *tokens, *chaintok, *headerstok, *blockstok, *ibdtok; |
|
|
const jsmntok_t *tokens, *chaintok, *headerstok, *blockstok, *ibdtok; |
|
|
struct json_stream *response; |
|
|
struct json_stream *response; |
|
|
bool valid, ibd; |
|
|
bool ibd; |
|
|
u32 headers, blocks; |
|
|
u32 headers, blocks; |
|
|
char *err; |
|
|
|
|
|
|
|
|
|
|
|
tokens = json_parse_input(bcli, bcli->output, bcli->output_bytes, |
|
|
tokens = json_parse_simple(bcli->output, |
|
|
&valid); |
|
|
bcli->output, bcli->output_bytes); |
|
|
if (!tokens) { |
|
|
if (!tokens) { |
|
|
err = tal_fmt(bcli->cmd, "%s: %s response (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, "cannot parse"); |
|
|
bcli_args(bcli), valid ? "partial" : "invalid", |
|
|
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (tokens[0].type != JSMN_OBJECT) { |
|
|
if (tokens[0].type != JSMN_OBJECT) { |
|
|
err = tal_fmt(bcli->cmd, "%s: gave non-object (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, "non-object"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
chaintok = json_get_member(bcli->output, tokens, "chain"); |
|
|
chaintok = json_get_member(bcli->output, tokens, "chain"); |
|
|
if (!chaintok) { |
|
|
if (!chaintok) { |
|
|
err = tal_fmt(bcli->cmd, "%s: bad 'chain' field (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, "missing chain member"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
headerstok = json_get_member(bcli->output, tokens, "headers"); |
|
|
headerstok = json_get_member(bcli->output, tokens, "headers"); |
|
|
if (!headerstok || !json_to_number(bcli->output, headerstok, &headers)) { |
|
|
if (!headerstok || !json_to_number(bcli->output, headerstok, &headers)) { |
|
|
err = tal_fmt(bcli->cmd, "%s: bad 'headers' field (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
"missing/bad headers member"); |
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
blockstok = json_get_member(bcli->output, tokens, "blocks"); |
|
|
blockstok = json_get_member(bcli->output, tokens, "blocks"); |
|
|
if (!blockstok || !json_to_number(bcli->output, blockstok, &blocks)) { |
|
|
if (!blockstok || !json_to_number(bcli->output, blockstok, &blocks)) { |
|
|
err = tal_fmt(bcli->cmd, "%s: bad 'blocks' field (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
"missing/bad blocks member"); |
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ibdtok = json_get_member(bcli->output, tokens, "initialblockdownload"); |
|
|
ibdtok = json_get_member(bcli->output, tokens, "initialblockdownload"); |
|
|
if (!ibdtok || !json_to_bool(bcli->output, ibdtok, &ibd)) { |
|
|
if (!ibdtok || !json_to_bool(bcli->output, ibdtok, &ibd)) { |
|
|
err = tal_fmt(bcli->cmd, "%s: bad 'initialblockdownload' field (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
"missing/bad initialblockdownload member"); |
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
response = jsonrpc_stream_success(bcli->cmd); |
|
|
response = jsonrpc_stream_success(bcli->cmd); |
|
@ -485,32 +458,21 @@ static struct command_result * |
|
|
estimatefees_parse_feerate(struct bitcoin_cli *bcli, u64 *feerate) |
|
|
estimatefees_parse_feerate(struct bitcoin_cli *bcli, u64 *feerate) |
|
|
{ |
|
|
{ |
|
|
const jsmntok_t *tokens, *feeratetok = NULL; |
|
|
const jsmntok_t *tokens, *feeratetok = NULL; |
|
|
bool valid; |
|
|
|
|
|
char *err; |
|
|
|
|
|
|
|
|
|
|
|
tokens = json_parse_input(bcli->output, bcli->output, |
|
|
tokens = json_parse_simple(bcli->output, |
|
|
(int)bcli->output_bytes, &valid); |
|
|
bcli->output, bcli->output_bytes); |
|
|
if (!tokens) { |
|
|
if (!tokens) { |
|
|
err = tal_fmt(bcli->cmd, "%s: %s response (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, "cannot parse"); |
|
|
bcli_args(bcli), valid ? "partial" : "invalid", |
|
|
|
|
|
(int)bcli->output_bytes, bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (tokens[0].type != JSMN_OBJECT) { |
|
|
if (tokens[0].type != JSMN_OBJECT) { |
|
|
err = tal_fmt(bcli->cmd, "%s: gave non-object (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, "non-object"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
feeratetok = json_get_member(bcli->output, tokens, "feerate"); |
|
|
feeratetok = json_get_member(bcli->output, tokens, "feerate"); |
|
|
if (feeratetok && |
|
|
if (feeratetok && |
|
|
!json_to_bitcoin_amount(bcli->output, feeratetok, feerate)) { |
|
|
!json_to_bitcoin_amount(bcli->output, feeratetok, feerate)) { |
|
|
err = tal_fmt(bcli->cmd, "%s: bad 'feerate' field (%.*s)", |
|
|
return command_err_bcli_badjson(bcli, "bad feerate"); |
|
|
bcli_args(bcli), (int)bcli->output_bytes, |
|
|
|
|
|
bcli->output); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} else if (!feeratetok) |
|
|
} else if (!feeratetok) |
|
|
/* We return null if estimation failed, and bitcoin-cli will
|
|
|
/* We return null if estimation failed, and bitcoin-cli will
|
|
|
* exit with 0 but no feerate field on failure. */ |
|
|
* exit with 0 but no feerate field on failure. */ |
|
@ -681,7 +643,7 @@ getrawblockbyheight_notfound(struct bitcoin_cli *bcli) |
|
|
|
|
|
|
|
|
static struct command_result *process_getblockhash(struct bitcoin_cli *bcli) |
|
|
static struct command_result *process_getblockhash(struct bitcoin_cli *bcli) |
|
|
{ |
|
|
{ |
|
|
const char *err, **params; |
|
|
const char **params; |
|
|
struct getrawblock_stash *stash = bcli->stash; |
|
|
struct getrawblock_stash *stash = bcli->stash; |
|
|
|
|
|
|
|
|
/* If it failed with error 8, give an empty response. */ |
|
|
/* If it failed with error 8, give an empty response. */ |
|
@ -696,9 +658,7 @@ static struct command_result *process_getblockhash(struct bitcoin_cli *bcli) |
|
|
stash->block_hash = tal_strndup(stash, bcli->output, |
|
|
stash->block_hash = tal_strndup(stash, bcli->output, |
|
|
bcli->output_bytes-1); |
|
|
bcli->output_bytes-1); |
|
|
if (!stash->block_hash || strlen(stash->block_hash) != 64) { |
|
|
if (!stash->block_hash || strlen(stash->block_hash) != 64) { |
|
|
err = tal_fmt(bcli->cmd, "%s: bad blockhash '%s'", |
|
|
return command_err_bcli_badjson(bcli, "bad blockhash"); |
|
|
bcli_args(bcli), stash->block_hash); |
|
|
|
|
|
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
params = tal_arr(bcli->cmd, const char *, 2); |
|
|
params = tal_arr(bcli->cmd, const char *, 2); |
|
@ -841,13 +801,11 @@ static void bitcoind_failure(struct plugin *p, const char *error_message) |
|
|
static void parse_getnetworkinfo_result(struct plugin *p, const char *buf) |
|
|
static void parse_getnetworkinfo_result(struct plugin *p, const char *buf) |
|
|
{ |
|
|
{ |
|
|
const jsmntok_t *result, *versiontok, *relaytok; |
|
|
const jsmntok_t *result, *versiontok, *relaytok; |
|
|
bool valid, tx_relay; |
|
|
bool tx_relay; |
|
|
u32 min_version = 160000; |
|
|
u32 min_version = 160000; |
|
|
|
|
|
|
|
|
result = json_parse_input(NULL, |
|
|
result = json_parse_simple(NULL, buf, strlen(buf)); |
|
|
buf, strlen(buf), |
|
|
if (!result) |
|
|
&valid); |
|
|
|
|
|
if (!result || !valid) |
|
|
|
|
|
plugin_err(p, "Invalid response to '%s': '%s'. Can not " |
|
|
plugin_err(p, "Invalid response to '%s': '%s'. Can not " |
|
|
"continue without proceeding to sanity checks.", |
|
|
"continue without proceeding to sanity checks.", |
|
|
gather_args(bitcoind, "getnetworkinfo", NULL), buf); |
|
|
gather_args(bitcoind, "getnetworkinfo", NULL), buf); |
|
|