diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 97f50b8b9a20..1276ea6dce6b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1383,6 +1383,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/autogenerate-rpc-examples.py b/tests/autogenerate-rpc-examples.py index 2d8be927aaa0..b7221de41b05 100644 --- a/tests/autogenerate-rpc-examples.py +++ b/tests/autogenerate-rpc-examples.py @@ -1914,7 +1914,7 @@ def generate_list_examples(l1, l2, l3, c12, c23_2, inv_l31, inv_l32, offer_l23, output['amount_msat'] = 201998900000 + (i * 1000) + (k * 100) update_example(node=l1, method='listtransactions', params={}, response=listtransactions_res1) listclosedchannels_res1 = l2.rpc.listclosedchannels() - listclosedchannels_res1 = update_list_responses(listclosedchannels_res1, list_key='closedchannels') + listclosedchannels_res1 = update_list_responses(listclosedchannels_res1, list_key='closedchannels', slice_upto=2, update_func=None, sort=True, sort_key='channel_id') for i, closedchannel in enumerate(listclosedchannels_res1['closedchannels'], start=1): closedchannel['last_commitment_fee_msat'] = 2894000 + (i * 1000) closedchannel['last_commitment_txid'] = 'txidcloselastcommitment0' + (('0000' + str(i)) * 8) diff --git a/tests/test_misc.py b/tests/test_misc.py index f1fe95119472..8398dbed2c74 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2975,6 +2975,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 @@ -3022,7 +3023,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) @@ -3143,7 +3147,10 @@ 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('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)