lightningd: add get_bitcoin_result for bcli response handling
Add `get_bitcoin_result` function that checks bcli plugin responses for errors and returns the result token. Previously, callbacks only detected errors when result parsing failed, ignoring the explicit error field from the plugin. Now we extract the actual error message from bcli, providing clearer reasoning when the plugin returns an error response.
This commit is contained in:
@@ -112,6 +112,35 @@ bitcoin_plugin_error(struct bitcoind *bitcoind, const char *buf,
|
||||
toks->end - toks->start, buf + toks->start);
|
||||
}
|
||||
|
||||
/* Check response for error (fatal if found) and return result token (fatal if not found). */
|
||||
static const jsmntok_t *get_bitcoin_result(struct bitcoind *bitcoind,
|
||||
const char *buf,
|
||||
const jsmntok_t *toks,
|
||||
const char *method)
|
||||
{
|
||||
const jsmntok_t *err_tok, *msg_tok, *result_tok;
|
||||
|
||||
err_tok = json_get_member(buf, toks, "error");
|
||||
if (err_tok) {
|
||||
msg_tok = json_get_member(buf, err_tok, "message");
|
||||
if (msg_tok)
|
||||
bitcoin_plugin_error(bitcoind, buf, toks, method,
|
||||
"%.*s", json_tok_full_len(msg_tok),
|
||||
json_tok_full(buf, msg_tok));
|
||||
else
|
||||
bitcoin_plugin_error(bitcoind, buf, toks, method,
|
||||
"%.*s", json_tok_full_len(err_tok),
|
||||
json_tok_full(buf, err_tok));
|
||||
}
|
||||
|
||||
result_tok = json_get_member(buf, toks, "result");
|
||||
if (!result_tok)
|
||||
bitcoin_plugin_error(bitcoind, buf, toks, method,
|
||||
"missing 'result' field");
|
||||
|
||||
return result_tok;
|
||||
}
|
||||
|
||||
/* Send a request to the Bitcoin plugin which registered that method,
|
||||
* if it's still alive. */
|
||||
static void bitcoin_plugin_send(struct bitcoind *bitcoind,
|
||||
@@ -227,11 +256,7 @@ static void estimatefees_callback(const char *buf, const jsmntok_t *toks,
|
||||
struct feerate_est *feerates;
|
||||
u32 floor;
|
||||
|
||||
resulttok = json_get_member(buf, toks, "result");
|
||||
if (!resulttok)
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks,
|
||||
"estimatefees",
|
||||
"bad 'result' field");
|
||||
resulttok = get_bitcoin_result(call->bitcoind, buf, toks, "estimatefees");
|
||||
|
||||
/* Modern style has floor. */
|
||||
floortok = json_get_member(buf, resulttok, "feerate_floor");
|
||||
@@ -315,21 +340,24 @@ static void sendrawtx_callback(const char *buf, const jsmntok_t *toks,
|
||||
const jsmntok_t *idtok,
|
||||
struct sendrawtx_call *call)
|
||||
{
|
||||
const jsmntok_t *resulttok;
|
||||
const char *err;
|
||||
const char *errmsg = NULL;
|
||||
bool success = false;
|
||||
|
||||
err = json_scan(tmpctx, buf, toks, "{result:{success:%}}",
|
||||
resulttok = get_bitcoin_result(call->bitcoind, buf, toks, "sendrawtransaction");
|
||||
|
||||
err = json_scan(tmpctx, buf, resulttok, "{success:%}",
|
||||
JSON_SCAN(json_to_bool, &success));
|
||||
if (err) {
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks,
|
||||
bitcoin_plugin_error(call->bitcoind, buf, resulttok,
|
||||
"sendrawtransaction",
|
||||
"bad 'result' field: %s", err);
|
||||
} else if (!success) {
|
||||
err = json_scan(tmpctx, buf, toks, "{result:{errmsg:%}}",
|
||||
err = json_scan(tmpctx, buf, resulttok, "{errmsg:%}",
|
||||
JSON_SCAN_TAL(tmpctx, json_strdup, &errmsg));
|
||||
if (err)
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks,
|
||||
bitcoin_plugin_error(call->bitcoind, buf, resulttok,
|
||||
"sendrawtransaction",
|
||||
"bad 'errmsg' field: %s",
|
||||
err);
|
||||
@@ -394,6 +422,7 @@ getrawblockbyheight_callback(const char *buf, const jsmntok_t *toks,
|
||||
const jsmntok_t *idtok,
|
||||
struct getrawblockbyheight_call *call)
|
||||
{
|
||||
const jsmntok_t *resulttok;
|
||||
const char *block_str, *err;
|
||||
struct bitcoin_blkid blkid;
|
||||
struct bitcoin_block *blk;
|
||||
@@ -401,6 +430,8 @@ getrawblockbyheight_callback(const char *buf, const jsmntok_t *toks,
|
||||
trace_span_resume(call);
|
||||
trace_span_end(call);
|
||||
|
||||
resulttok = get_bitcoin_result(call->bitcoind, buf, toks, "getrawblockbyheight");
|
||||
|
||||
/* Callback may free parent of call, so steal onto context to
|
||||
* free if it doesn't */
|
||||
ctx = tal(NULL, char);
|
||||
@@ -408,24 +439,24 @@ getrawblockbyheight_callback(const char *buf, const jsmntok_t *toks,
|
||||
|
||||
/* If block hash is `null`, this means not found! Call the callback
|
||||
* with NULL values. */
|
||||
err = json_scan(tmpctx, buf, toks, "{result:{blockhash:null}}");
|
||||
err = json_scan(tmpctx, buf, resulttok, "{blockhash:null}");
|
||||
if (!err) {
|
||||
call->cb(call->bitcoind, call->height, NULL, NULL, call->cb_arg);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
err = json_scan(tmpctx, buf, toks, "{result:{blockhash:%,block:%}}",
|
||||
err = json_scan(tmpctx, buf, resulttok, "{blockhash:%,block:%}",
|
||||
JSON_SCAN(json_to_sha256, &blkid.shad.sha),
|
||||
JSON_SCAN_TAL(tmpctx, json_strdup, &block_str));
|
||||
if (err)
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks,
|
||||
bitcoin_plugin_error(call->bitcoind, buf, resulttok,
|
||||
"getrawblockbyheight",
|
||||
"bad 'result' field: %s", err);
|
||||
|
||||
blk = bitcoin_block_from_hex(tmpctx, chainparams, block_str,
|
||||
strlen(block_str));
|
||||
if (!blk)
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks,
|
||||
bitcoin_plugin_error(call->bitcoind, buf, resulttok,
|
||||
"getrawblockbyheight",
|
||||
"bad block");
|
||||
|
||||
@@ -494,18 +525,21 @@ static void getchaininfo_callback(const char *buf, const jsmntok_t *toks,
|
||||
const jsmntok_t *idtok,
|
||||
struct getchaininfo_call *call)
|
||||
{
|
||||
const jsmntok_t *resulttok;
|
||||
const char *err, *chain;
|
||||
u32 headers, blocks;
|
||||
bool ibd;
|
||||
|
||||
err = json_scan(tmpctx, buf, toks,
|
||||
"{result:{chain:%,headercount:%,blockcount:%,ibd:%}}",
|
||||
resulttok = get_bitcoin_result(call->bitcoind, buf, toks, "getchaininfo");
|
||||
|
||||
err = json_scan(tmpctx, buf, resulttok,
|
||||
"{chain:%,headercount:%,blockcount:%,ibd:%}",
|
||||
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)
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks, "getchaininfo",
|
||||
bitcoin_plugin_error(call->bitcoind, buf, resulttok, "getchaininfo",
|
||||
"bad 'result' field: %s", err);
|
||||
|
||||
call->cb(call->bitcoind, chain, headers, blocks, ibd,
|
||||
@@ -565,24 +599,27 @@ static void getutxout_callback(const char *buf, const jsmntok_t *toks,
|
||||
const jsmntok_t *idtok,
|
||||
struct getutxout_call *call)
|
||||
{
|
||||
const jsmntok_t *resulttok;
|
||||
const char *err;
|
||||
struct bitcoin_tx_output txout;
|
||||
|
||||
/* Whatever happens, we want to free this. */
|
||||
tal_steal(tmpctx, call);
|
||||
|
||||
err = json_scan(tmpctx, buf, toks, "{result:{script:null}}");
|
||||
resulttok = get_bitcoin_result(call->bitcoind, buf, toks, "getutxout");
|
||||
|
||||
err = json_scan(tmpctx, buf, resulttok, "{script:null}");
|
||||
if (!err) {
|
||||
call->cb(call->bitcoind, NULL, call->cb_arg);
|
||||
return;
|
||||
}
|
||||
|
||||
err = json_scan(tmpctx, buf, toks, "{result:{script:%,amount:%}}",
|
||||
err = json_scan(tmpctx, buf, resulttok, "{script:%,amount:%}",
|
||||
JSON_SCAN_TAL(tmpctx, json_tok_bin_from_hex,
|
||||
&txout.script),
|
||||
JSON_SCAN(json_to_sat, &txout.amount));
|
||||
if (err)
|
||||
bitcoin_plugin_error(call->bitcoind, buf, toks, "getutxout",
|
||||
bitcoin_plugin_error(call->bitcoind, buf, resulttok, "getutxout",
|
||||
"bad 'result' field: %s", err);
|
||||
|
||||
call->cb(call->bitcoind, &txout, call->cb_arg);
|
||||
|
||||
Reference in New Issue
Block a user