mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
bitcoind: allow processing callbacks to indicate that a failure is spurious.
In particular, process_getblockhash() exits with status 8 when the block number is out of range, which is expected. Any other exit status should be treated as a spurious error. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
7c8883ae7d
commit
0204c44243
@ -16,6 +16,7 @@
|
|||||||
#include <ccan/tal/tal.h>
|
#include <ccan/tal/tal.h>
|
||||||
#include <common/json.h>
|
#include <common/json.h>
|
||||||
#include <common/memleak.h>
|
#include <common/memleak.h>
|
||||||
|
#include <common/timeout.h>
|
||||||
#include <common/utils.h>
|
#include <common/utils.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -77,7 +78,7 @@ struct bitcoin_cli {
|
|||||||
char *output;
|
char *output;
|
||||||
size_t output_bytes;
|
size_t output_bytes;
|
||||||
size_t new_output;
|
size_t new_output;
|
||||||
void (*process)(struct bitcoin_cli *);
|
bool (*process)(struct bitcoin_cli *);
|
||||||
void *cb;
|
void *cb;
|
||||||
void *cb_arg;
|
void *cb_arg;
|
||||||
struct bitcoin_cli **stopper;
|
struct bitcoin_cli **stopper;
|
||||||
@ -115,10 +116,36 @@ static char *bcli_args(struct bitcoin_cli *bcli)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We allow 60 seconds of spurious errors, eg. reorg. */
|
||||||
|
static void bcli_failure(struct bitcoind *bitcoind,
|
||||||
|
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(60)))
|
||||||
|
fatal("%s exited %u (after %u other errors) '%.*s'",
|
||||||
|
bcli_args(bcli),
|
||||||
|
exitstatus,
|
||||||
|
bitcoind->error_count,
|
||||||
|
(int)bcli->output_bytes,
|
||||||
|
bcli->output);
|
||||||
|
|
||||||
|
log_unusual(bitcoind->log,
|
||||||
|
"%s exited with status %u", bcli_args(bcli), exitstatus);
|
||||||
|
|
||||||
|
bitcoind->error_count++;
|
||||||
|
}
|
||||||
|
|
||||||
static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli)
|
static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
int ret, status;
|
int ret, status;
|
||||||
struct bitcoind *bitcoind = bcli->bitcoind;
|
struct bitcoind *bitcoind = bcli->bitcoind;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
/* FIXME: If we waited for SIGCHILD, this could never hang! */
|
/* FIXME: If we waited for SIGCHILD, this could never hang! */
|
||||||
ret = waitpid(bcli->pid, &status, 0);
|
ret = waitpid(bcli->pid, &status, 0);
|
||||||
@ -133,27 +160,7 @@ static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli)
|
|||||||
|
|
||||||
if (!bcli->exitstatus) {
|
if (!bcli->exitstatus) {
|
||||||
if (WEXITSTATUS(status) != 0) {
|
if (WEXITSTATUS(status) != 0) {
|
||||||
/* Allow 60 seconds of spurious errors, eg. reorg. */
|
bcli_failure(bitcoind, bcli, WEXITSTATUS(status));
|
||||||
struct timerel t;
|
|
||||||
|
|
||||||
log_unusual(bcli->bitcoind->log,
|
|
||||||
"%s exited with status %u",
|
|
||||||
bcli_args(bcli),
|
|
||||||
WEXITSTATUS(status));
|
|
||||||
|
|
||||||
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(60)))
|
|
||||||
fatal("%s exited %u (after %u other errors) '%.*s'",
|
|
||||||
bcli_args(bcli),
|
|
||||||
WEXITSTATUS(status),
|
|
||||||
bitcoind->error_count,
|
|
||||||
(int)bcli->output_bytes,
|
|
||||||
bcli->output);
|
|
||||||
bitcoind->error_count++;
|
|
||||||
bitcoind->req_running = false;
|
bitcoind->req_running = false;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -170,9 +177,12 @@ static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
db_begin_transaction(bitcoind->ld->wallet->db);
|
db_begin_transaction(bitcoind->ld->wallet->db);
|
||||||
bcli->process(bcli);
|
ok = bcli->process(bcli);
|
||||||
db_commit_transaction(bitcoind->ld->wallet->db);
|
db_commit_transaction(bitcoind->ld->wallet->db);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
bcli_failure(bitcoind, bcli, WEXITSTATUS(status));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
tal_free(bcli);
|
tal_free(bcli);
|
||||||
|
|
||||||
@ -202,8 +212,9 @@ static void next_bcli(struct bitcoind *bitcoind)
|
|||||||
io_set_finish(conn, bcli_finished, bcli);
|
io_set_finish(conn, bcli_finished, bcli);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_donothing(struct bitcoin_cli *bcli UNUSED)
|
static bool process_donothing(struct bitcoin_cli *bcli UNUSED)
|
||||||
{
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If stopper gets freed first, set process() to a noop. */
|
/* If stopper gets freed first, set process() to a noop. */
|
||||||
@ -220,11 +231,12 @@ static void remove_stopper(struct bitcoin_cli *bcli)
|
|||||||
tal_free(bcli->stopper);
|
tal_free(bcli->stopper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If ctx is non-NULL, and is freed before we return, we don't call process() */
|
/* 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
|
static void
|
||||||
start_bitcoin_cli(struct bitcoind *bitcoind,
|
start_bitcoin_cli(struct bitcoind *bitcoind,
|
||||||
const tal_t *ctx,
|
const tal_t *ctx,
|
||||||
void (*process)(struct bitcoin_cli *),
|
bool (*process)(struct bitcoin_cli *),
|
||||||
bool nonzero_exit_ok,
|
bool nonzero_exit_ok,
|
||||||
void *cb, void *cb_arg,
|
void *cb, void *cb_arg,
|
||||||
char *cmd, ...)
|
char *cmd, ...)
|
||||||
@ -299,7 +311,7 @@ struct estimatefee {
|
|||||||
static void do_one_estimatefee(struct bitcoind *bitcoind,
|
static void do_one_estimatefee(struct bitcoind *bitcoind,
|
||||||
struct estimatefee *efee);
|
struct estimatefee *efee);
|
||||||
|
|
||||||
static void process_estimatefee(struct bitcoin_cli *bcli)
|
static bool process_estimatefee(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
double feerate;
|
double feerate;
|
||||||
struct estimatefee *efee = bcli->cb_arg;
|
struct estimatefee *efee = bcli->cb_arg;
|
||||||
@ -321,6 +333,7 @@ static void process_estimatefee(struct bitcoin_cli *bcli)
|
|||||||
/* Next */
|
/* Next */
|
||||||
do_one_estimatefee(bcli->bitcoind, efee);
|
do_one_estimatefee(bcli->bitcoind, efee);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_one_estimatefee(struct bitcoind *bitcoind,
|
static void do_one_estimatefee(struct bitcoind *bitcoind,
|
||||||
@ -354,7 +367,7 @@ void bitcoind_estimate_fees_(struct bitcoind *bitcoind,
|
|||||||
do_one_estimatefee(bitcoind, efee);
|
do_one_estimatefee(bitcoind, efee);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_sendrawtx(struct bitcoin_cli *bcli)
|
static bool process_sendrawtx(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
int, const char *msg, void *) = bcli->cb;
|
int, const char *msg, void *) = bcli->cb;
|
||||||
@ -365,6 +378,7 @@ static void process_sendrawtx(struct bitcoin_cli *bcli)
|
|||||||
*bcli->exitstatus, msg);
|
*bcli->exitstatus, msg);
|
||||||
|
|
||||||
cb(bcli->bitcoind, *bcli->exitstatus, msg, bcli->cb_arg);
|
cb(bcli->bitcoind, *bcli->exitstatus, msg, bcli->cb_arg);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
|
void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
|
||||||
@ -378,14 +392,13 @@ void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
|
|||||||
"sendrawtransaction", hextx, NULL);
|
"sendrawtransaction", hextx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_rawblock(struct bitcoin_cli *bcli)
|
static bool process_rawblock(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
struct bitcoin_block *blk;
|
struct bitcoin_block *blk;
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
struct bitcoin_block *blk,
|
struct bitcoin_block *blk,
|
||||||
void *arg) = bcli->cb;
|
void *arg) = bcli->cb;
|
||||||
|
|
||||||
/* FIXME: Just get header if we can't get full block. */
|
|
||||||
blk = bitcoin_block_from_hex(bcli, bcli->output, bcli->output_bytes);
|
blk = bitcoin_block_from_hex(bcli, bcli->output, bcli->output_bytes);
|
||||||
if (!blk)
|
if (!blk)
|
||||||
fatal("%s: bad block '%.*s'?",
|
fatal("%s: bad block '%.*s'?",
|
||||||
@ -393,6 +406,7 @@ static void process_rawblock(struct bitcoin_cli *bcli)
|
|||||||
(int)bcli->output_bytes, bcli->output);
|
(int)bcli->output_bytes, bcli->output);
|
||||||
|
|
||||||
cb(bcli->bitcoind, blk, bcli->cb_arg);
|
cb(bcli->bitcoind, blk, bcli->cb_arg);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoind_getrawblock_(struct bitcoind *bitcoind,
|
void bitcoind_getrawblock_(struct bitcoind *bitcoind,
|
||||||
@ -409,7 +423,7 @@ void bitcoind_getrawblock_(struct bitcoind *bitcoind,
|
|||||||
"getblock", hex, "false", NULL);
|
"getblock", hex, "false", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_getblockcount(struct bitcoin_cli *bcli)
|
static bool process_getblockcount(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
u32 blockcount;
|
u32 blockcount;
|
||||||
char *p, *end;
|
char *p, *end;
|
||||||
@ -424,6 +438,7 @@ static void process_getblockcount(struct bitcoin_cli *bcli)
|
|||||||
bcli_args(bcli), p);
|
bcli_args(bcli), p);
|
||||||
|
|
||||||
cb(bcli->bitcoind, blockcount, bcli->cb_arg);
|
cb(bcli->bitcoind, blockcount, bcli->cb_arg);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoind_getblockcount_(struct bitcoind *bitcoind,
|
void bitcoind_getblockcount_(struct bitcoind *bitcoind,
|
||||||
@ -452,7 +467,7 @@ static void process_get_output(struct bitcoind *bitcoind, const struct bitcoin_t
|
|||||||
go->cb(bitcoind, txout, go->cbarg);
|
go->cb(bitcoind, txout, go->cbarg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_gettxout(struct bitcoin_cli *bcli)
|
static bool process_gettxout(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
const struct bitcoin_tx_output *output,
|
const struct bitcoin_tx_output *output,
|
||||||
@ -467,7 +482,7 @@ static void process_gettxout(struct bitcoin_cli *bcli)
|
|||||||
log_debug(bcli->bitcoind->log, "%s: not unspent output?",
|
log_debug(bcli->bitcoind->log, "%s: not unspent output?",
|
||||||
bcli_args(bcli));
|
bcli_args(bcli));
|
||||||
cb(bcli->bitcoind, NULL, bcli->cb_arg);
|
cb(bcli->bitcoind, NULL, bcli->cb_arg);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid);
|
tokens = json_parse_input(bcli->output, bcli->output_bytes, &valid);
|
||||||
@ -504,6 +519,7 @@ static void process_gettxout(struct bitcoin_cli *bcli)
|
|||||||
bcli_args(bcli), (int)bcli->output_bytes, bcli->output);
|
bcli_args(bcli), (int)bcli->output_bytes, bcli->output);
|
||||||
|
|
||||||
cb(bcli->bitcoind, &out, bcli->cb_arg);
|
cb(bcli->bitcoind, &out, bcli->cb_arg);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -512,7 +528,7 @@ static void process_gettxout(struct bitcoin_cli *bcli)
|
|||||||
* Used to resolve a `txoutput` after identifying the blockhash, and
|
* Used to resolve a `txoutput` after identifying the blockhash, and
|
||||||
* before extracting the outpoint from the UTXO.
|
* before extracting the outpoint from the UTXO.
|
||||||
*/
|
*/
|
||||||
static void process_getblock(struct bitcoin_cli *bcli)
|
static bool process_getblock(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
const struct bitcoin_tx_output *output,
|
const struct bitcoin_tx_output *output,
|
||||||
@ -532,7 +548,7 @@ static void process_getblock(struct bitcoin_cli *bcli)
|
|||||||
bcli_args(bcli));
|
bcli_args(bcli));
|
||||||
cb(bcli->bitcoind, NULL, cbarg);
|
cb(bcli->bitcoind, NULL, cbarg);
|
||||||
tal_free(go);
|
tal_free(go);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokens[0].type != JSMN_OBJECT)
|
if (tokens[0].type != JSMN_OBJECT)
|
||||||
@ -556,7 +572,7 @@ static void process_getblock(struct bitcoin_cli *bcli)
|
|||||||
bcli_args(bcli), go->txnum);
|
bcli_args(bcli), go->txnum);
|
||||||
cb(bcli->bitcoind, NULL, cbarg);
|
cb(bcli->bitcoind, NULL, cbarg);
|
||||||
tal_free(go);
|
tal_free(go);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bitcoin_txid_from_hex(bcli->output + txidtok->start,
|
if (!bitcoin_txid_from_hex(bcli->output + txidtok->start,
|
||||||
@ -570,9 +586,10 @@ static void process_getblock(struct bitcoin_cli *bcli)
|
|||||||
go->cb = cb;
|
go->cb = cb;
|
||||||
/* Now get the raw tx output. */
|
/* Now get the raw tx output. */
|
||||||
bitcoind_gettxout(bcli->bitcoind, &txid, go->outnum, process_get_output, go);
|
bitcoind_gettxout(bcli->bitcoind, &txid, go->outnum, process_get_output, go);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_getblockhash_for_txout(struct bitcoin_cli *bcli)
|
static bool process_getblockhash_for_txout(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
const struct bitcoin_tx_output *output,
|
const struct bitcoin_tx_output *output,
|
||||||
@ -585,13 +602,14 @@ static void process_getblockhash_for_txout(struct bitcoin_cli *bcli)
|
|||||||
bcli_args(bcli));
|
bcli_args(bcli));
|
||||||
tal_free(go);
|
tal_free(go);
|
||||||
cb(bcli->bitcoind, NULL, cbarg);
|
cb(bcli->bitcoind, NULL, cbarg);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_bitcoin_cli(bcli->bitcoind, NULL, process_getblock, false, cb, go,
|
start_bitcoin_cli(bcli->bitcoind, NULL, process_getblock, false, cb, go,
|
||||||
"getblock",
|
"getblock",
|
||||||
take(tal_strndup(go, bcli->output,bcli->output_bytes)),
|
take(tal_strndup(go, bcli->output,bcli->output_bytes)),
|
||||||
NULL);
|
NULL);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoind_getoutput_(struct bitcoind *bitcoind,
|
void bitcoind_getoutput_(struct bitcoind *bitcoind,
|
||||||
@ -618,17 +636,20 @@ void bitcoind_getoutput_(struct bitcoind *bitcoind,
|
|||||||
notleak(go);
|
notleak(go);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_getblockhash(struct bitcoin_cli *bcli)
|
static bool process_getblockhash(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
struct bitcoin_blkid blkid;
|
struct bitcoin_blkid blkid;
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
const struct bitcoin_blkid *blkid,
|
const struct bitcoin_blkid *blkid,
|
||||||
void *arg) = bcli->cb;
|
void *arg) = bcli->cb;
|
||||||
|
|
||||||
/* If it failed, call with NULL block. */
|
/* If it failed with error 8, call with NULL block. */
|
||||||
if (*bcli->exitstatus != 0) {
|
if (*bcli->exitstatus != 0) {
|
||||||
|
/* Other error means we have to retry. */
|
||||||
|
if (*bcli->exitstatus != 8)
|
||||||
|
return false;
|
||||||
cb(bcli->bitcoind, NULL, bcli->cb_arg);
|
cb(bcli->bitcoind, NULL, bcli->cb_arg);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bcli->output_bytes == 0
|
if (bcli->output_bytes == 0
|
||||||
@ -639,6 +660,7 @@ static void process_getblockhash(struct bitcoin_cli *bcli)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cb(bcli->bitcoind, &blkid, bcli->cb_arg);
|
cb(bcli->bitcoind, &blkid, bcli->cb_arg);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoind_getblockhash_(struct bitcoind *bitcoind,
|
void bitcoind_getblockhash_(struct bitcoind *bitcoind,
|
||||||
|
Loading…
Reference in New Issue
Block a user