bcli: convert `sendrawtransaction` to synchronous execution
What changed, and why it matters
This commit changes how Core Lightning submits raw Bitcoin transactions to the local bitcoin node. Previously it was done in the background (asynchronous); now it is done inline (synchronous) and returns the result directly. The change is a refactor that makes error handling more explicit and helps functional tests observe failures. There is no direct evidence in the commit that this fixes an exploitable security bug.
No immediate security action required. Review as part of normal release testing; verify that synchronous bitcoin-cli calls do not introduce head-of-line blocking or timeout issues for transaction broadcast.
Security signals we found
Behavioral refactor of transaction broadcast path
Adds explicit error-message surfacing from bitcoin-cli to RPC response
Removes asynchronous pending-command pattern for sendrawtransaction
Evidence from the diff
The patch converts sendrawtransaction in plugins/bcli.c from an async start_bitcoin_cli + process_sendrawtransaction callback pattern to a synchronous run_bitcoin_cli call. It now builds the JSON response inline, marks success true if the exit status is 0 or RPC_TRANSACTION_ALREADY_IN_CHAIN, and includes any bitcoin-cli stderr output as errmsg. The old callback is marked UNNEEDED but left in place. The change improves determinism for tests and surfaces bitcoin-cli exit status/logging.
Changed components
plugins/bcli.csendrawtransaction RPC handlerInspect captured patch +22 / −6
diff --git a/plugins/bcli.c b/plugins/bcli.c
index 899cd1a8..ce0d6c12 100644
--- a/plugins/bcli.c
+++ b/plugins/bcli.c
@@ -632,7 +632,7 @@ estimatefees_parse_feerate(struct bitcoin_cli *bcli, u64 *feerate)
return NULL;
}
-static struct command_result *process_sendrawtransaction(struct bitcoin_cli *bcli)
+static UNNEEDED struct command_result *process_sendrawtransaction(struct bitcoin_cli *bcli)
{
struct json_stream *response;
@@ -1094,6 +1094,8 @@ static struct command_result *sendrawtransaction(struct command *cmd,
{
const char *tx, *highfeesarg;
bool *allowhighfees;
+ struct bcli_result *res;
+ struct json_stream *response;
/* bitcoin-cli wants strings. */
if (!param(cmd, buf, toks,
@@ -1107,12 +1109,26 @@ static struct command_result *sendrawtransaction(struct command *cmd,
} else
highfeesarg = NULL;
- start_bitcoin_cli(NULL, cmd, process_sendrawtransaction, true,
- BITCOIND_HIGH_PRIO, NULL,
- "sendrawtransaction",
- tx, highfeesarg, NULL);
+ res = run_bitcoin_cli(cmd, cmd->plugin,
+ "sendrawtransaction", tx, highfeesarg, NULL);
- return command_still_pending(cmd);
+ /* This is useful for functional tests. */
+ if (res->exitstatus)
+ plugin_log(cmd->plugin, LOG_DBG,
+ "sendrawtx exit %i (%s)",
+ res->exitstatus,
+ res->output);
+
+ response = jsonrpc_stream_success(cmd);
+ json_add_bool(response, "success",
+ res->exitstatus == 0 ||
+ res->exitstatus == RPC_TRANSACTION_ALREADY_IN_CHAIN);
+ json_add_string(response, "errmsg",
+ res->exitstatus ?
+ tal_strndup(cmd, res->output, res->output_len)
+ : "");
+
+ return command_finished(cmd, response);
}
static struct command_result *getutxout(struct command *cmd,
Why this scored 16/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.