bcli: remove unused async code after sync refactor
What changed, and why it matters
This commit is mostly a cleanup: it removes old asynchronous code from the bitcoin-cli plugin after it was converted to run commands one at a time (synchronously). The only functional bug fix is adding a missing `close(from)` call, which stops a file descriptor leak when running bitcoin-cli. There is no obvious new security vulnerability introduced by the change.
No immediate action required beyond normal review and testing. The cleanup reduces attack surface; verify the synchronous refactor did not introduce regressions in error handling or retry behavior.
Security signals we found
File descriptor leak fixed in `run_bitcoin_cliv` and `wait_and_check_bitcoind` by adding `close(from)`
Removal of async I/O and concurrency control reduces complexity and potential race conditions
`waitpid` error handling improved: non-EINTR failures now call `plugin_err` instead of looping silently
No new input parsing, network exposure, or cryptographic operations introduced
Evidence from the diff
The diff removes the async I/O infrastructure (io_*, bitcoin_cli struct, pending/in-flight queues, priority scheduling, async callbacks) from plugins/bcli.c following a prior synchronous refactor. It also fixes a file descriptor leak by closing from in run_bitcoin_cliv() and in wait_and_check_bitcoind(). The waitpid loop now handles non-EINTR errors by fatal error instead of silently spinning. No new unsafe primitives or externally reachable attack surface is added.
Changed components
plugins/bcli.cbitcoin-cli backend plugin (bcli)Inspect captured patch +15 / −705
diff --git a/plugins/bcli.c b/plugins/bcli.c
index 2510ebd9..4616c58b 100644
--- a/plugins/bcli.c
+++ b/plugins/bcli.c
@@ -1,7 +1,6 @@
#include "config.h"
#include <ccan/array_size/array_size.h>
#include <ccan/cast/cast.h>
-#include <ccan/io/io.h>
#include <ccan/pipecmd/pipecmd.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/tal/grab_file/grab_file.h>
@@ -12,21 +11,10 @@
#include <errno.h>
#include <inttypes.h>
#include <plugins/libplugin.h>
+#include <unistd.h>
-/* 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;
Why this scored 21/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.