Skip to content

Commit

Permalink
bitcoind: detect when it's still syncing, add field to getinfo.
Browse files Browse the repository at this point in the history
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell authored and cdecker committed Aug 10, 2019
1 parent be8ebf2 commit faded9a
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
98 changes: 98 additions & 0 deletions lightningd/bitcoind.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions lightningd/bitcoind.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down
5 changes: 5 additions & 0 deletions lightningd/peer_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
21 changes: 21 additions & 0 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,27 @@ def crash_bitcoincli(r):
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)

Expand Down

0 comments on commit faded9a

Please sign in to comment.