diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 56ea80828a9a..129bd8cdf28e 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1377,6 +1377,32 @@ static void connect_activate_subd(struct lightningd *ld, struct channel *channel send_error: log_debug(channel->log, "Telling connectd to send error %s", tal_hex(tmpctx, error)); + + /* LND does not respond to errors with a unilateral close + * (https://github.com/lightningnetwork/lnd/blob/abb1e3463f3a83bbb843d5c399869dbe930ad94f/htlcswitch/link.go#L2119). + * We fix this by sending a `ChannelReestablish` msg with `0` commitment numbers and an + * invalid `your_last_per_commitment_secret`. */ + if (is_stub_scid(*channel->scid)) { + struct secret your_last_per_commit_secret; + memset(&your_last_per_commit_secret, 1, + sizeof(your_last_per_commit_secret)); + + const u8 *msg = towire_channel_reestablish(tmpctx, &channel->cid, + 0, + 0, + &your_last_per_commit_secret, + &channel->channel_info.remote_per_commit, + NULL); + + log_debug(channel->log, "Sending a bogus channel_reestablish message to make the peer " + "unilaterally close the channel."); + + subd_send_msg(ld->connectd, + take(towire_connectd_peer_send_msg(NULL, &channel->peer->id, + channel->peer->connectd_counter, + msg))); + } + /* Get connectd to send error and close. */ subd_send_msg(ld->connectd, take(towire_connectd_peer_send_msg(NULL, &channel->peer->id, diff --git a/tests/test_misc.py b/tests/test_misc.py index fc01ca883d34..615e5e1d3ff4 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2979,6 +2979,7 @@ def test_emergencyrecoverpenaltytxn(node_factory, bitcoind): stubs = l1.rpc.emergencyrecover()["stubs"] assert len(stubs) == 1 assert stubs[0] == _["channel_id"] + l1.daemon.wait_for_log('Sending a bogus channel_reestablish message to make the peer unilaterally close the channel.') l1.daemon.wait_for_log('peer_out WIRE_ERROR') # Restarting so that L1 @@ -3026,7 +3027,10 @@ def test_emergencyrecover(node_factory, bitcoind): listfunds = l1.rpc.listfunds()["channels"][0] assert listfunds["short_channel_id"] == "1x1x1" + l1.daemon.wait_for_log('Sending a bogus channel_reestablish message to make the peer unilaterally close the channel.') l1.daemon.wait_for_log('peer_out WIRE_ERROR') + + l2.daemon.wait_for_log('bad reestablish commitment_number: 0') l2.daemon.wait_for_log('State changed from CHANNELD_NORMAL to AWAITING_UNILATERAL') bitcoind.generate_block(5, wait_for_mempool=1) @@ -3147,7 +3151,9 @@ def test_restorefrompeer(node_factory, bitcoind): assert l1.rpc.restorefrompeer()['stubs'][0] == _['channel_id'] + l1.daemon.wait_for_log('Sending a bogus channel_reestablish message to make the peer unilaterally close the channel.') l1.daemon.wait_for_log('peer_out WIRE_ERROR') + l2.daemon.wait_for_log('State changed from CHANNELD_NORMAL to AWAITING_UNILATERAL') bitcoind.generate_block(5, wait_for_mempool=1)