lightningd: don't allow channeld to accept HTLCs if we're not synced.

We want to still allow incoming connections, and reestablishment of
channels, but if one tries to give us an HTLC, stall until we're
synced.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2019-08-10 20:18:13 +09:30 committed by Christian Decker
parent 6195a878f7
commit c3a35416da
3 changed files with 51 additions and 2 deletions

View File

@ -1442,6 +1442,18 @@ static bool peer_sending_revocation(struct channel *channel,
return true;
}
struct deferred_commitsig {
struct channel *channel;
const u8 *msg;
};
static void retry_deferred_commitsig(struct chain_topology *topo,
struct deferred_commitsig *d)
{
peer_got_commitsig(d->channel, d->msg);
tal_free(d);
}
/* This also implies we're sending revocation */
void peer_got_commitsig(struct channel *channel, const u8 *msg)
{
@ -1458,6 +1470,24 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
size_t i;
struct lightningd *ld = channel->peer->ld;
/* If we're not synced with bitcoin network, we can't accept
* any HTLCs. We stall at this point, in the hope that it
* won't take long! */
if (!topology_synced(ld->topology)) {
struct deferred_commitsig *d;
log_unusual(channel->log,
"Deferring incoming commit until we sync");
/* If subdaemon dies, we want to forget this. */
d = tal(channel->owner, struct deferred_commitsig);
d->channel = channel;
d->msg = tal_dup_arr(d, u8, msg, tal_count(msg), 0);
topology_add_sync_waiter(d, ld->topology,
retry_deferred_commitsig, d);
return;
}
if (!fromwire_channel_got_commitsig(msg, msg,
&commitnum,
&feerate,

View File

@ -154,10 +154,14 @@ def test_lightningd_still_loading(node_factory, bitcoind, executor):
# Start it, establish channel.
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True})
# Balance channel.
l1.pay(l2, 10**9 // 2)
l1.stop()
# Now make sure it's behind.
bitcoind.generate_block(2)
# Make sure l2 is synced
sync_blockheight(bitcoind, [l2])
# Make it slow grabbing the final block.
slow_blockid = bitcoind.rpc.getblockhash(bitcoind.rpc.getblockcount())
@ -173,9 +177,17 @@ def test_lightningd_still_loading(node_factory, bitcoind, executor):
with pytest.raises(RpcError, match=r'TEMPORARY_CHANNEL_FAILURE'):
l1.pay(l2, 1000)
# Release the mock, and it will recover.
# This will work, but will be delayed until synced.
fut = executor.submit(l2.pay, l1, 1000)
l1.daemon.wait_for_log("Deferring incoming commit until we sync")
# Release the mock.
mock_release.set()
wait_for(lambda: 'warning_lightningd_sync' not in l1.rpc.getinfo())
fut.result()
assert 'warning_lightningd_sync' not in l1.rpc.getinfo()
# This will now work normally.
l1.pay(l2, 1000)

View File

@ -527,6 +527,13 @@ void subd_req_(const tal_t *ctx UNNEEDED,
/* Generated stub for subd_send_msg */
void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED)
{ fprintf(stderr, "subd_send_msg called!\n"); abort(); }
/* Generated stub for topology_add_sync_waiter_ */
void topology_add_sync_waiter_(const tal_t *ctx UNNEEDED,
struct chain_topology *topo UNNEEDED,
void (*cb)(struct chain_topology *topo UNNEEDED,
void *arg) UNNEEDED,
void *arg UNNEEDED)
{ fprintf(stderr, "topology_add_sync_waiter_ called!\n"); abort(); }
/* Generated stub for towire_channel_dev_memleak */
u8 *towire_channel_dev_memleak(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channel_dev_memleak called!\n"); abort(); }