diff --git a/plugins/bcli.c b/plugins/bcli.c index 2510ebd95..4616c58b5 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -1,7 +1,6 @@ #include "config.h" #include #include -#include #include #include #include @@ -12,21 +11,10 @@ #include #include #include +#include -/* Bitcoind's web server has a default of 4 threads, with queue depth 16. - * It will *fail* rather than queue beyond that, so we must not stress it! - * - * This is how many request for each priority level we have. - */ -#define BITCOIND_MAX_PARALLEL 4 #define RPC_TRANSACTION_ALREADY_IN_CHAIN -27 -enum bitcoind_prio { - BITCOIND_LOW_PRIO, - BITCOIND_HIGH_PRIO -}; -#define BITCOIND_NUM_PRIO (BITCOIND_HIGH_PRIO+1) - struct bitcoind { /* eg. "bitcoin-cli" */ char *cli; @@ -37,22 +25,6 @@ struct bitcoind { /* bitcoind's version, used for compatibility checks. */ u32 version; - /* Is bitcoind synced? If not, we retry. */ - bool synced; - - /* How many high/low prio requests are we running (it's ratelimited) */ - size_t num_requests[BITCOIND_NUM_PRIO]; - - /* Pending requests (high and low prio). */ - struct list_head pending[BITCOIND_NUM_PRIO]; - - /* In flight requests (in a list for memleak detection) */ - struct list_head current; - - /* If non-zero, time we first hit a bitcoind error. */ - unsigned int error_count; - struct timemono first_error_time; - /* How long to keep trying to contact bitcoind * before fatally exiting. */ u64 retry_timeout; @@ -73,24 +45,6 @@ struct bitcoind { static struct bitcoind *bitcoind; -struct bitcoin_cli { - struct list_node list; - int fd; - int *exitstatus; - pid_t pid; - const char **args; - const char **stdinargs; - struct timemono start; - enum bitcoind_prio prio; - char *output; - size_t output_bytes; - size_t new_output; - struct command_result *(*process)(struct bitcoin_cli *); - struct command *cmd; - /* Used to stash content between multiple calls */ - void *stash; -}; - /* Result of a synchronous bitcoin-cli call */ struct bcli_result { char *output; @@ -171,25 +125,6 @@ gather_args(const tal_t *ctx, const char ***stdinargs, const char *cmd, ...) return ret; } -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 next_bcli(enum bitcoind_prio prio); - /* For printing: simple string of args (no secrets!) */ static char *args_string(const tal_t *ctx, const char **args, const char **stdinargs) { @@ -251,9 +186,15 @@ run_bitcoin_cliv(const tal_t *ctx, res->output = grab_fd_str(res, from); res->output_len = strlen(res->output); res->args = args_string(res, cmd, stdinargs); + close(from); /* Wait for child to exit */ - while (waitpid(child, &status, 0) < 0 && errno == EINTR); + while (waitpid(child, &status, 0) < 0) { + if (errno == EINTR) + continue; + plugin_err(plugin, "waitpid(%s) failed: %s", + res->args, strerror(errno)); + } if (!WIFEXITED(status)) plugin_err(plugin, "%s died with signal %i", @@ -279,202 +220,6 @@ run_bitcoin_cli(const tal_t *ctx, return res; } -static char *bcli_args(const tal_t *ctx, struct bitcoin_cli *bcli) -{ - return args_string(ctx, bcli->args, bcli->stdinargs); -} - -/* Only set as destructor once bcli is in current. */ -static void destroy_bcli(struct bitcoin_cli *bcli) -{ - list_del_from(&bitcoind->current, &bcli->list); -} - -static struct command_result *retry_bcli(struct command *cmd, - struct bitcoin_cli *bcli) -{ - list_del_from(&bitcoind->current, &bcli->list); - tal_del_destructor(bcli, destroy_bcli); - - list_add_tail(&bitcoind->pending[bcli->prio], &bcli->list); - tal_free(bcli->output); - next_bcli(bcli->prio); - return timer_complete(cmd); -} - -/* We allow 60 seconds of spurious errors, eg. reorg. */ -static void bcli_failure(struct bitcoin_cli *bcli, - int exitstatus) -{ - struct timerel t; - - if (!bitcoind->error_count) - bitcoind->first_error_time = time_mono(); - - t = timemono_between(time_mono(), bitcoind->first_error_time); - if (time_greater(t, time_from_sec(bitcoind->retry_timeout))) - plugin_err(bcli->cmd->plugin, - "%s exited %u (after %u other errors) '%.*s'; " - "we have been retrying command for " - "--bitcoin-retry-timeout=%"PRIu64" seconds; " - "bitcoind setup or our --bitcoin-* configs broken?", - bcli_args(tmpctx, bcli), - exitstatus, - bitcoind->error_count, - (int)bcli->output_bytes, - bcli->output, - bitcoind->retry_timeout); - - plugin_log(bcli->cmd->plugin, LOG_UNUSUAL, "%s exited with status %u", - bcli_args(tmpctx, bcli), exitstatus); - bitcoind->error_count++; - - /* Retry in 1 second */ - command_timer(bcli->cmd, time_from_sec(1), retry_bcli, bcli); -} - -static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli) -{ - int ret, status; - struct command_result *res; - enum bitcoind_prio prio = bcli->prio; - u64 msec = time_to_msec(timemono_between(time_mono(), bcli->start)); - - /* If it took over 10 seconds, that's rather strange. */ - if (msec > 10000) - plugin_log(bcli->cmd->plugin, LOG_UNUSUAL, - "bitcoin-cli: finished %s (%"PRIu64" ms)", - bcli_args(tmpctx, bcli), msec); - - assert(bitcoind->num_requests[prio] > 0); - - /* FIXME: If we waited for SIGCHILD, this could never hang! */ - while ((ret = waitpid(bcli->pid, &status, 0)) < 0 && errno == EINTR); - if (ret != bcli->pid) - plugin_err(bcli->cmd->plugin, "%s %s", bcli_args(tmpctx, bcli), - ret == 0 ? "not exited?" : strerror(errno)); - - if (!WIFEXITED(status)) - plugin_err(bcli->cmd->plugin, "%s died with signal %i", - bcli_args(tmpctx, bcli), - WTERMSIG(status)); - - /* Implicit nonzero_exit_ok == false */ - if (!bcli->exitstatus) { - if (WEXITSTATUS(status) != 0) { - bcli_failure(bcli, WEXITSTATUS(status)); - bitcoind->num_requests[prio]--; - goto done; - } - } else - *bcli->exitstatus = WEXITSTATUS(status); - - if (WEXITSTATUS(status) == 0) - bitcoind->error_count = 0; - - bitcoind->num_requests[bcli->prio]--; - - res = bcli->process(bcli); - if (!res) - bcli_failure(bcli, WEXITSTATUS(status)); - else - tal_free(bcli); - -done: - next_bcli(prio); -} - -static void next_bcli(enum bitcoind_prio prio) -{ - struct bitcoin_cli *bcli; - struct io_conn *conn; - int in; - - if (bitcoind->num_requests[prio] >= BITCOIND_MAX_PARALLEL) - return; - - bcli = list_pop(&bitcoind->pending[prio], struct bitcoin_cli, list); - if (!bcli) - return; - - bcli->pid = pipecmdarr(&in, &bcli->fd, &bcli->fd, - cast_const2(char **, bcli->args)); - if (bcli->pid < 0) - plugin_err(bcli->cmd->plugin, "%s exec failed: %s", - bcli->args[0], strerror(errno)); - - - if (bitcoind->rpcpass) { - write_all(in, bitcoind->rpcpass, strlen(bitcoind->rpcpass)); - write_all(in, "\n", strlen("\n")); - } - for (size_t i = 0; i < tal_count(bcli->stdinargs); i++) { - write_all(in, bcli->stdinargs[i], strlen(bcli->stdinargs[i])); - write_all(in, "\n", strlen("\n")); - } - close(in); - - bcli->start = time_mono(); - - bitcoind->num_requests[prio]++; - - /* We don't keep a pointer to this, but it's not a leak */ - conn = notleak(io_new_conn(bcli, bcli->fd, output_init, bcli)); - io_set_finish(conn, bcli_finished, bcli); - - list_add_tail(&bitcoind->current, &bcli->list); - tal_add_destructor(bcli, destroy_bcli); -} - -static void -start_bitcoin_cliv(const tal_t *ctx, - struct command *cmd, - struct command_result *(*process)(struct bitcoin_cli *), - bool nonzero_exit_ok, - enum bitcoind_prio prio, - void *stash, - const char *method, - va_list ap) -{ - struct bitcoin_cli *bcli = tal(bitcoind, struct bitcoin_cli); - - bcli->process = process; - bcli->cmd = cmd; - bcli->prio = prio; - - if (nonzero_exit_ok) - bcli->exitstatus = tal(bcli, int); - else - bcli->exitstatus = NULL; - - bcli->stdinargs = tal_arr(bcli, const char *, 0); - bcli->args = gather_argsv(bcli, &bcli->stdinargs, method, ap); - bcli->stash = stash; - - list_add_tail(&bitcoind->pending[bcli->prio], &bcli->list); - next_bcli(bcli->prio); -} - -/* If ctx is non-NULL, and is freed before we return, we don't call process(). - * process returns false() if it's a spurious error, and we should retry. */ -static void LAST_ARG_NULL -start_bitcoin_cli(const tal_t *ctx, - struct command *cmd, - struct command_result *(*process)(struct bitcoin_cli *), - bool nonzero_exit_ok, - enum bitcoind_prio prio, - void *stash, - const char *method, - ...) -{ - va_list ap; - - va_start(ap, method); - start_bitcoin_cliv(ctx, cmd, process, nonzero_exit_ok, prio, stash, method, - ap); - va_end(ap); -} - static void strip_trailing_whitespace(char *str, size_t len) { size_t stripped_len = len; @@ -484,15 +229,6 @@ static void strip_trailing_whitespace(char *str, size_t len) str[stripped_len] = 0x00; } -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(tmpctx, bcli), errmsg, - (int)bcli->output_bytes, bcli->output); - return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); -} - static struct command_result *command_err(struct command *cmd, struct bcli_result *res, const char *errmsg) @@ -508,80 +244,6 @@ static void json_add_null(struct json_stream *stream, const char *fieldname) json_add_primitive(stream, fieldname, "null"); } -static UNNEEDED struct command_result *process_getutxout(struct bitcoin_cli *bcli) -{ - const jsmntok_t *tokens; - struct json_stream *response; - struct bitcoin_tx_output output; - const char *err; - - /* As of at least v0.15.1.0, bitcoind returns "success" but an empty - string on a spent txout. */ - if (*bcli->exitstatus != 0 || bcli->output_bytes == 0) { - response = jsonrpc_stream_success(bcli->cmd); - json_add_null(response, "amount"); - json_add_null(response, "script"); - - return command_finished(bcli->cmd, response); - } - - tokens = json_parse_simple(bcli->output, bcli->output, - bcli->output_bytes); - if (!tokens) { - return command_err_bcli_badjson(bcli, "cannot parse"); - } - - err = json_scan(tmpctx, bcli->output, tokens, - "{value:%,scriptPubKey:{hex:%}}", - JSON_SCAN(json_to_bitcoin_amount, - &output.amount.satoshis), /* Raw: bitcoind */ - JSON_SCAN_TAL(bcli, json_tok_bin_from_hex, - &output.script)); - if (err) - return command_err_bcli_badjson(bcli, err); - - response = jsonrpc_stream_success(bcli->cmd); - json_add_sats(response, "amount", output.amount); - json_add_string(response, "script", tal_hex(response, output.script)); - - return command_finished(bcli->cmd, response); -} - -static UNNEEDED struct command_result *process_getblockchaininfo(struct bitcoin_cli *bcli) -{ - const jsmntok_t *tokens; - struct json_stream *response; - bool ibd; - u32 headers, blocks; - const char *chain, *err; - - tokens = json_parse_simple(bcli->output, - bcli->output, bcli->output_bytes); - if (!tokens) { - return command_err_bcli_badjson(bcli, "cannot parse"); - } - - err = json_scan(tmpctx, bcli->output, tokens, - "{chain:%,headers:%,blocks:%,initialblockdownload:%}", - JSON_SCAN_TAL(tmpctx, json_strdup, &chain), - JSON_SCAN(json_to_number, &headers), - JSON_SCAN(json_to_number, &blocks), - JSON_SCAN(json_to_bool, &ibd)); - if (err) - return command_err_bcli_badjson(bcli, err); - - if (bitcoind->dev_ignore_ibd) - ibd = false; - - response = jsonrpc_stream_success(bcli->cmd); - json_add_string(response, "chain", chain); - json_add_u32(response, "headercount", headers); - json_add_u32(response, "blockcount", blocks); - json_add_bool(response, "ibd", ibd); - - return command_finished(bcli->cmd, response); -} - struct estimatefee_params { u32 blocks; const char *style; @@ -594,14 +256,6 @@ static const struct estimatefee_params estimatefee_params[] = { { 100, "ECONOMICAL" }, }; -struct estimatefees_stash { - /* This is max(mempoolminfee,minrelaytxfee) */ - u64 perkb_floor; - u32 cursor; - /* FIXME: We use u64 but lightningd will store them as u32. */ - u64 perkb[ARRAY_SIZE(estimatefee_params)]; -}; - static struct command_result * estimatefees_null_response(struct command *cmd) { @@ -615,228 +269,6 @@ estimatefees_null_response(struct command *cmd) return command_finished(cmd, response); } -static UNNEEDED struct command_result * -estimatefees_parse_feerate(struct bitcoin_cli *bcli, u64 *feerate) -{ - const jsmntok_t *tokens; - - tokens = json_parse_simple(bcli->output, - bcli->output, bcli->output_bytes); - if (!tokens) { - return command_err_bcli_badjson(bcli, "cannot parse"); - } - - if (json_scan(tmpctx, bcli->output, tokens, "{feerate:%}", - JSON_SCAN(json_to_bitcoin_amount, feerate)) != NULL) { - /* Paranoia: if it had a feerate, but was malformed: */ - if (json_get_member(bcli->output, tokens, "feerate")) - return command_err_bcli_badjson(bcli, "cannot scan"); - /* Regtest fee estimation is generally awful: Fake it at min. */ - if (bitcoind->fake_fees) { - *feerate = 1000; - return NULL; - } - /* We return null if estimation failed, and bitcoin-cli will - * exit with 0 but no feerate field on failure. */ - return estimatefees_null_response(bcli->cmd); - } - - return NULL; -} - -static UNNEEDED struct command_result *process_sendrawtransaction(struct bitcoin_cli *bcli) -{ - struct json_stream *response; - - /* This is useful for functional tests. */ - if (bcli->exitstatus) - plugin_log(bcli->cmd->plugin, LOG_DBG, - "sendrawtx exit %i (%s) %.*s", - *bcli->exitstatus, bcli_args(tmpctx, bcli), - *bcli->exitstatus ? - (u32)bcli->output_bytes-1 : 0, - bcli->output); - - response = jsonrpc_stream_success(bcli->cmd); - json_add_bool(response, "success", - *bcli->exitstatus == 0 || - *bcli->exitstatus == - RPC_TRANSACTION_ALREADY_IN_CHAIN); - json_add_string(response, "errmsg", - *bcli->exitstatus ? - tal_strndup(bcli->cmd, - bcli->output, bcli->output_bytes-1) - : ""); - - return command_finished(bcli->cmd, response); -} - -struct getrawblock_stash { - const char *block_hash; - u32 block_height; - const char *block_hex; - int *peers; -}; - -/* Mutual recursion. */ -static UNNEEDED struct command_result *getrawblock(struct bitcoin_cli *bcli); - -static UNNEEDED struct command_result *process_rawblock(struct bitcoin_cli *bcli) -{ - struct json_stream *response; - struct getrawblock_stash *stash = bcli->stash; - - strip_trailing_whitespace(bcli->output, bcli->output_bytes); - stash->block_hex = tal_steal(stash, bcli->output); - - response = jsonrpc_stream_success(bcli->cmd); - json_add_string(response, "blockhash", stash->block_hash); - json_add_string(response, "block", stash->block_hex); - - return command_finished(bcli->cmd, response); -} - -static UNNEEDED struct command_result *process_getblockfrompeer(struct bitcoin_cli *bcli) -{ - /* Remove the peer that we tried to get the block from and move along, - * we may also check on errors here */ - struct getrawblock_stash *stash = bcli->stash; - - if (bcli->exitstatus && *bcli->exitstatus != 0) { - /* We still continue with the execution if we can not fetch the - * block from peer */ - plugin_log(bcli->cmd->plugin, LOG_DBG, - "failed to fetch block %s from peer %i, skip.", - stash->block_hash, stash->peers[tal_count(stash->peers) - 1]); - } else { - plugin_log(bcli->cmd->plugin, LOG_DBG, - "try to fetch block %s from peer %i.", - stash->block_hash, stash->peers[tal_count(stash->peers) - 1]); - } - tal_resize(&stash->peers, tal_count(stash->peers) - 1); - - /* `getblockfrompeer` is an async call. sleep for a second to allow the - * block to be delivered by the peer. fixme: We could also sleep for - * double the last ping here (with sanity limit)*/ - sleep(1); - - return getrawblock(bcli); -} - -static UNNEEDED struct command_result *process_getpeerinfo(struct bitcoin_cli *bcli) -{ - const jsmntok_t *t, *toks; - struct getrawblock_stash *stash = bcli->stash; - size_t i; - - toks = - json_parse_simple(bcli->output, bcli->output, bcli->output_bytes); - - if (!toks) { - return command_err_bcli_badjson(bcli, "cannot parse"); - } - - stash->peers = tal_arr(bcli->stash, int, 0); - - json_for_each_arr(i, t, toks) - { - int id; - u8 *services; - - if (json_scan(tmpctx, bcli->output, t, "{id:%,services:%}", - JSON_SCAN(json_to_int, &id), - JSON_SCAN_TAL(tmpctx, json_tok_bin_from_hex, &services)) == NULL) { - /* From bitcoin source: - * // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently - * // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients. - * NODE_NETWORK = (1 << 0) - */ - if (tal_count(services) > 0 && (services[tal_count(services)-1] & (1<<0))) { - // fixme: future optimization: sort by last ping - tal_arr_expand(&stash->peers, id); - } - } - } - - if (tal_count(stash->peers) <= 0) { - /* We don't have peers yet, retry from `getrawblock` */ - plugin_log(bcli->cmd->plugin, LOG_DBG, - "got an empty peer list."); - return getrawblock(bcli); - } - - start_bitcoin_cli(NULL, bcli->cmd, process_getblockfrompeer, true, - BITCOIND_HIGH_PRIO, stash, "getblockfrompeer", - stash->block_hash, - take(tal_fmt(NULL, "%i", stash->peers[tal_count(stash->peers) - 1])), NULL); - - return command_still_pending(bcli->cmd); -} - -static UNNEEDED struct command_result *process_getrawblock(struct bitcoin_cli *bcli) -{ - /* We failed to get the raw block. */ - if (bcli->exitstatus && *bcli->exitstatus != 0) { - struct getrawblock_stash *stash = bcli->stash; - - plugin_log(bcli->cmd->plugin, LOG_DBG, - "failed to fetch block %s from the bitcoin backend (maybe pruned).", - stash->block_hash); - - if (bitcoind->version >= 230000) { - /* `getblockformpeer` was introduced in v23.0.0 */ - - if (!stash->peers) { - /* We don't have peers to fetch blocks from, get - * some! */ - start_bitcoin_cli(NULL, bcli->cmd, - process_getpeerinfo, true, - BITCOIND_HIGH_PRIO, stash, - "getpeerinfo", NULL); - - return command_still_pending(bcli->cmd); - } - - if (tal_count(stash->peers) > 0) { - /* We have peers left that we can ask for the - * block */ - start_bitcoin_cli( - NULL, bcli->cmd, process_getblockfrompeer, - true, BITCOIND_HIGH_PRIO, stash, - "getblockfrompeer", stash->block_hash, - take(tal_fmt(NULL, "%i", stash->peers[tal_count(stash->peers) - 1])), - NULL); - - return command_still_pending(bcli->cmd); - } - - /* We failed to fetch the block from from any peer we - * got. */ - plugin_log( - bcli->cmd->plugin, LOG_DBG, - "asked all known peers about block %s, retry", - stash->block_hash); - stash->peers = tal_free(stash->peers); - } - - return NULL; - } - - return process_rawblock(bcli); -} - -static UNNEEDED struct command_result * -getrawblockbyheight_notfound_bcli(struct bitcoin_cli *bcli) -{ - struct json_stream *response; - - response = jsonrpc_stream_success(bcli->cmd); - json_add_null(response, "blockhash"); - json_add_null(response, "block"); - - return command_finished(bcli->cmd, response); -} - static struct command_result * getrawblockbyheight_notfound(struct command *cmd) { @@ -849,40 +281,6 @@ getrawblockbyheight_notfound(struct command *cmd) return command_finished(cmd, response); } -static UNNEEDED struct command_result *getrawblock(struct bitcoin_cli *bcli) -{ - struct getrawblock_stash *stash = bcli->stash; - - start_bitcoin_cli(NULL, bcli->cmd, process_getrawblock, true, - BITCOIND_HIGH_PRIO, stash, "getblock", - stash->block_hash, - /* Non-verbose: raw block. */ - "0", NULL); - - return command_still_pending(bcli->cmd); -} - -static UNNEEDED struct command_result *process_getblockhash(struct bitcoin_cli *bcli) -{ - struct getrawblock_stash *stash = bcli->stash; - - /* If it failed with error 8, give an empty response. */ - if (bcli->exitstatus && *bcli->exitstatus != 0) { - /* Other error means we have to retry. */ - if (*bcli->exitstatus != 8) - return NULL; - return getrawblockbyheight_notfound_bcli(bcli); - } - - strip_trailing_whitespace(bcli->output, bcli->output_bytes); - stash->block_hash = tal_strdup(stash, bcli->output); - if (!stash->block_hash || strlen(stash->block_hash) != 64) { - return command_err_bcli_badjson(bcli, "bad blockhash"); - } - - return getrawblock(bcli); -} - /* Get peers that support NODE_NETWORK (full nodes). * Returns array of peer ids, or empty array if none found. */ static int *get_fullnode_peers(const tal_t *ctx, struct command *cmd) @@ -1081,9 +479,6 @@ static struct command_result *getchaininfo(struct command *cmd, return command_finished(cmd, response); } -/* Mutual recursion. */ -static struct command_result *estimatefees_done(struct bitcoin_cli *bcli); - /* Add a feerate, but don't publish one that bitcoind won't accept. */ static void json_add_feerate(struct json_stream *result, const char *fieldname, struct command *cmd, @@ -1110,69 +505,6 @@ static void json_add_feerate(struct json_stream *result, const char *fieldname, } } -static UNNEEDED struct command_result *estimatefees_next(struct command *cmd, - struct estimatefees_stash *stash) -{ - struct json_stream *response; - - if (stash->cursor < ARRAY_SIZE(stash->perkb)) { - start_bitcoin_cli(NULL, cmd, estimatefees_done, true, - BITCOIND_LOW_PRIO, stash, - "estimatesmartfee", - take(tal_fmt(NULL, "%u", - estimatefee_params[stash->cursor].blocks)), - estimatefee_params[stash->cursor].style, - NULL); - - return command_still_pending(cmd); - } - - response = jsonrpc_stream_success(cmd); - /* Present an ordered array of block deadlines, and a floor. */ - json_array_start(response, "feerates"); - for (size_t i = 0; i < ARRAY_SIZE(stash->perkb); i++) { - if (!stash->perkb[i]) - continue; - json_object_start(response, NULL); - json_add_u32(response, "blocks", estimatefee_params[i].blocks); - json_add_feerate(response, "feerate", cmd, stash->perkb_floor, stash->perkb[i]); - json_object_end(response); - } - json_array_end(response); - json_add_u64(response, "feerate_floor", stash->perkb_floor); - return command_finished(cmd, response); -} - -static UNNEEDED struct command_result *getminfees_done(struct bitcoin_cli *bcli) -{ - const jsmntok_t *tokens; - const char *err; - u64 mempoolfee, relayfee; - struct estimatefees_stash *stash = bcli->stash; - - if (*bcli->exitstatus != 0) - return estimatefees_null_response(bcli->cmd); - - tokens = json_parse_simple(bcli->output, - bcli->output, bcli->output_bytes); - if (!tokens) - return command_err_bcli_badjson(bcli, - "cannot parse getmempoolinfo"); - - /* Look at minrelaytxfee they configured, and current min fee to get - * into mempool. */ - err = json_scan(tmpctx, bcli->output, tokens, - "{mempoolminfee:%,minrelaytxfee:%}", - JSON_SCAN(json_to_bitcoin_amount, &mempoolfee), - JSON_SCAN(json_to_bitcoin_amount, &relayfee)); - if (err) - return command_err_bcli_badjson(bcli, err); - - stash->perkb_floor = max_u64(mempoolfee, relayfee); - stash->cursor = 0; - return estimatefees_next(bcli->cmd, stash); -} - /* Get the feerate floor from getmempoolinfo. * Returns NULL on success (floor stored in *perkb_floor), or error response. */ static struct command_result *get_feerate_floor(struct command *cmd, @@ -1248,7 +580,7 @@ static struct command_result *estimatefees(struct command *cmd, const jsmntok_t *toks UNUSED) { struct command_result *err; - u64 perkb_floor; + u64 perkb_floor = 0; u64 perkb[ARRAY_SIZE(estimatefee_params)]; struct json_stream *response; @@ -1281,23 +613,6 @@ static struct command_result *estimatefees(struct command *cmd, return command_finished(cmd, response); } -static UNNEEDED struct command_result *estimatefees_done(struct bitcoin_cli *bcli) -{ - struct command_result *err; - struct estimatefees_stash *stash = bcli->stash; - - /* If we cannot estimate fees, no need to continue bothering bitcoind. */ - if (*bcli->exitstatus != 0) - return estimatefees_null_response(bcli->cmd); - - err = estimatefees_parse_feerate(bcli, &stash->perkb[stash->cursor]); - if (err) - return err; - - stash->cursor++; - return estimatefees_next(bcli->cmd, stash); -} - /* Send a transaction to the Bitcoin network. * Calls `sendrawtransaction` using the first parameter as the raw tx. */ @@ -1326,11 +641,11 @@ static struct command_result *sendrawtransaction(struct command *cmd, "sendrawtransaction", tx, highfeesarg, NULL); /* This is useful for functional tests. */ - if (res->exitstatus) - plugin_log(cmd->plugin, LOG_DBG, - "sendrawtx exit %i (%s)", - res->exitstatus, - res->output); + plugin_log(cmd->plugin, LOG_DBG, + "sendrawtx exit %i (%s) %.*s", + res->exitstatus, res->args, + res->exitstatus ? (int)res->output_len : 0, + res->output); response = jsonrpc_stream_success(cmd); json_add_bool(response, "success", @@ -1468,6 +783,7 @@ static void wait_and_check_bitcoind(struct plugin *p) } output = grab_fd_str(cmd, from); + close(from); waitpid(child, &status, 0); @@ -1543,12 +859,6 @@ static struct bitcoind *new_bitcoind(const tal_t *ctx) bitcoind->cli = NULL; bitcoind->datadir = NULL; - for (size_t i = 0; i < BITCOIND_NUM_PRIO; i++) { - bitcoind->num_requests[i] = 0; - list_head_init(&bitcoind->pending[i]); - } - list_head_init(&bitcoind->current); - bitcoind->error_count = 0; bitcoind->retry_timeout = 60; bitcoind->rpcuser = NULL; bitcoind->rpcpass = NULL;