mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
bitcoind: detect when it's still syncing, add field to getinfo.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
be8ebf2667
commit
faded9a9cf
@ -997,6 +997,103 @@ void bitcoind_getclientversion(struct bitcoind *bitcoind)
|
||||
"getnetworkinfo", NULL);
|
||||
}
|
||||
|
||||
/* Mutual recursion */
|
||||
static bool process_getblockchaininfo(struct bitcoin_cli *bcli);
|
||||
|
||||
static void retry_getblockchaininfo(struct bitcoind *bitcoind)
|
||||
{
|
||||
assert(!bitcoind->synced);
|
||||
start_bitcoin_cli(bitcoind, NULL,
|
||||
process_getblockchaininfo,
|
||||
false, BITCOIND_LOW_PRIO, NULL, NULL,
|
||||
"getblockchaininfo", NULL);
|
||||
}
|
||||
|
||||
/* Given JSON object from getblockchaininfo, are we synced? Poll if not. */
|
||||
static void is_bitcoind_synced_yet(struct bitcoind *bitcoind,
|
||||
const char *output, size_t output_len,
|
||||
const jsmntok_t *obj,
|
||||
bool initial)
|
||||
{
|
||||
const jsmntok_t *t;
|
||||
unsigned int headers, blocks;
|
||||
bool ibd;
|
||||
|
||||
t = json_get_member(output, obj, "headers");
|
||||
if (!t || !json_to_number(output, t, &headers))
|
||||
fatal("Invalid 'headers' field in getblockchaininfo '%.*s'",
|
||||
(int)output_len, output);
|
||||
|
||||
t = json_get_member(output, obj, "blocks");
|
||||
if (!t || !json_to_number(output, t, &blocks))
|
||||
fatal("Invalid 'blocks' field in getblockchaininfo '%.*s'",
|
||||
(int)output_len, output);
|
||||
|
||||
t = json_get_member(output, obj, "initialblockdownload");
|
||||
if (!t || !json_to_bool(output, t, &ibd))
|
||||
fatal("Invalid 'initialblockdownload' field in getblockchaininfo '%.*s'",
|
||||
(int)output_len, output);
|
||||
|
||||
if (ibd) {
|
||||
if (initial)
|
||||
log_unusual(bitcoind->log,
|
||||
"Waiting for initial block download"
|
||||
" (this can take a while!)");
|
||||
else
|
||||
log_debug(bitcoind->log,
|
||||
"Still waiting for initial block download");
|
||||
} else if (headers != blocks) {
|
||||
if (initial)
|
||||
log_unusual(bitcoind->log,
|
||||
"Waiting for bitcoind to catch up"
|
||||
" (%u blocks of %u)",
|
||||
blocks, headers);
|
||||
else
|
||||
log_debug(bitcoind->log,
|
||||
"Waiting for bitcoind to catch up"
|
||||
" (%u blocks of %u)",
|
||||
blocks, headers);
|
||||
} else {
|
||||
if (!initial)
|
||||
log_info(bitcoind->log, "Bitcoind now synced.");
|
||||
bitcoind->synced = true;
|
||||
return;
|
||||
}
|
||||
|
||||
bitcoind->synced = false;
|
||||
notleak(new_reltimer(bitcoind->ld->timers, bitcoind,
|
||||
/* Be 4x more aggressive in this case. */
|
||||
time_divide(time_from_sec(bitcoind->ld->topology
|
||||
->poll_seconds), 4),
|
||||
retry_getblockchaininfo, bitcoind));
|
||||
}
|
||||
|
||||
static bool process_getblockchaininfo(struct bitcoin_cli *bcli)
|
||||
{
|
||||
const jsmntok_t *tokens;
|
||||
bool valid;
|
||||
|
||||
tokens = json_parse_input(bcli, bcli->output, bcli->output_bytes,
|
||||
&valid);
|
||||
if (!tokens)
|
||||
fatal("%s: %s response (%.*s)",
|
||||
bcli_args(tmpctx, bcli),
|
||||
valid ? "partial" : "invalid",
|
||||
(int)bcli->output_bytes, bcli->output);
|
||||
|
||||
if (tokens[0].type != JSMN_OBJECT) {
|
||||
log_unusual(bcli->bitcoind->log,
|
||||
"%s: gave non-object (%.*s)?",
|
||||
bcli_args(tmpctx, bcli),
|
||||
(int)bcli->output_bytes, bcli->output);
|
||||
return false;
|
||||
}
|
||||
|
||||
is_bitcoind_synced_yet(bcli->bitcoind, bcli->output, bcli->output_bytes,
|
||||
tokens, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void destroy_bitcoind(struct bitcoind *bitcoind)
|
||||
{
|
||||
/* Suppresses the callbacks from bcli_finished as we free conns. */
|
||||
@ -1073,6 +1170,7 @@ static char* check_blockchain_from_bitcoincli(const tal_t *ctx,
|
||||
" Should be: %s",
|
||||
bitcoind->chainparams->bip70_name);
|
||||
|
||||
is_bitcoind_synced_yet(bitcoind, output, output_bytes, tokens, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,9 @@ struct bitcoind {
|
||||
/* Main lightningd structure */
|
||||
struct lightningd *ld;
|
||||
|
||||
/* 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];
|
||||
|
||||
|
@ -1553,6 +1553,11 @@ static struct command_result *json_getinfo(struct command *cmd,
|
||||
wallet_total_forward_fees(cmd->ld->wallet),
|
||||
"msatoshi_fees_collected",
|
||||
"fees_collected_msat");
|
||||
|
||||
if (!cmd->ld->topology->bitcoind->synced)
|
||||
json_add_string(response, "warning_bitcoind_sync",
|
||||
"Bitcoind is not up-to-date with network.");
|
||||
|
||||
return command_success(cmd, response);
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,27 @@ def test_bitcoin_failure(node_factory, bitcoind):
|
||||
sync_blockheight(bitcoind, [l1])
|
||||
|
||||
|
||||
def test_bitcoin_ibd(node_factory, bitcoind):
|
||||
"""Test that we recognize bitcoin in initial download mode"""
|
||||
info = bitcoind.rpc.getblockchaininfo()
|
||||
info['initialblockdownload'] = True
|
||||
|
||||
l1 = node_factory.get_node(start=False)
|
||||
l1.daemon.rpcproxy.mock_rpc('getblockchaininfo', info)
|
||||
|
||||
l1.start()
|
||||
|
||||
# This happens before the Starting message start() waits for.
|
||||
assert l1.daemon.is_in_log('Waiting for initial block download')
|
||||
assert 'warning_bitcoind_sync' in l1.rpc.getinfo()
|
||||
|
||||
# "Finish" IDB.
|
||||
l1.daemon.rpcproxy.mock_rpc('getblockchaininfo', None)
|
||||
|
||||
l1.daemon.wait_for_log('Bitcoind now synced')
|
||||
assert 'warning_bitcoind_sync' not in l1.rpc.getinfo()
|
||||
|
||||
|
||||
def test_ping(node_factory):
|
||||
l1, l2 = node_factory.line_graph(2, fundchannel=False)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user