diff --git a/contrib/pylightning/lightning/lightning.py b/contrib/pylightning/lightning/lightning.py index aa506bb79..bfd29e843 100644 --- a/contrib/pylightning/lightning/lightning.py +++ b/contrib/pylightning/lightning/lightning.py @@ -342,6 +342,9 @@ class LightningRpc(UnixDomainSocketRpc): if len(args) >= 1: if isinstance(args[0], bool): return self._deprecated_close(peer_id, *args, **kwargs) + if len(args) == 2: + if args[0] is None and isinstance(args[1], int): + return self._deprecated_close(peer_id, *args, **kwargs) def _close(peer_id, unilateraltimeout=None, destination=None): payload = { diff --git a/tests/test_closing.py b/tests/test_closing.py index 5aed70d7a..c7317eb4b 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -297,6 +297,70 @@ def test_closing_negotiation_reconnect(node_factory, bitcoind): assert bitcoind.rpc.getmempoolinfo()['size'] == 1 +@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") +def test_closing_specified_destination(node_factory, bitcoind): + l1, l2, l3, l4 = node_factory.get_nodes(4) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.rpc.connect(l3.info['id'], 'localhost', l3.port) + l1.rpc.connect(l4.info['id'], 'localhost', l4.port) + + chan12 = l1.fund_channel(l2, 10**6) + chan13 = l1.fund_channel(l3, 10**6) + chan14 = l1.fund_channel(l4, 10**6) + + l1.pay(l2, 100000000) + l1.pay(l3, 100000000) + l1.pay(l4, 100000000) + + bitcoind.generate_block(5) + addr = 'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg' + l1.rpc.close(chan12, None, addr) + l1.rpc.call('close', {'id': chan13, 'destination': addr}) + l1.rpc.call('close', [chan14, None, addr]) + + l1.daemon.wait_for_logs([' to CLOSINGD_SIGEXCHANGE'] * 3) + + # Both nodes should have disabled the channel in their view + wait_for(lambda: len(l1.getactivechannels()) == 0) + + assert bitcoind.rpc.getmempoolinfo()['size'] == 3 + + # Now grab the close transaction + closetxid = bitcoind.rpc.getrawmempool(False) + assert len(closetxid) == 3 + + idindex = {} + for n in [l2, l3, l4]: + billboard = only_one(l1.rpc.listpeers(n.info['id'])['peers'][0]['channels'])['status'] + idindex[n] = [i for i in range(3) if billboard == [ + 'CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 5430 satoshi for tx:{}'.format(closetxid[i]), + ]][0] + assert idindex[n] in range(3) + + bitcoind.generate_block(1) + sync_blockheight(bitcoind, [l1, l2, l3, l4]) + + # l1 can't spent the output to addr. + assert not l1.daemon.is_in_log(r'Owning output.* \(SEGWIT\).* txid %s.* CONFIRMED' % closetxid[0]) + assert not l1.daemon.is_in_log(r'Owning output.* \(SEGWIT\).* txid %s.* CONFIRMED' % closetxid[1]) + assert not l1.daemon.is_in_log(r'Owning output.* \(SEGWIT\).* txid %s.* CONFIRMED' % closetxid[2]) + # Check the txid has at least 1 confirmation + l2.daemon.wait_for_log(r'Owning output.* \(SEGWIT\).* txid %s.* CONFIRMED' % closetxid[idindex[l2]]) + l3.daemon.wait_for_log(r'Owning output.* \(SEGWIT\).* txid %s.* CONFIRMED' % closetxid[idindex[l3]]) + l4.daemon.wait_for_log(r'Owning output.* \(SEGWIT\).* txid %s.* CONFIRMED' % closetxid[idindex[l4]]) + + for n in [l2, l3, l4]: + # Make sure both nodes have grabbed their close tx funds + outputs = n.rpc.listfunds()['outputs'] + assert closetxid[idindex[n]] in set([o['txid'] for o in outputs]) + output_num2 = [o for o in outputs if o['txid'] == closetxid[idindex[n]]][0]['output'] + output_num1 = 0 if output_num2 == 1 else 1 + # Check the another address is addr + assert addr == bitcoind.rpc.gettxout(closetxid[idindex[n]], output_num1)['scriptPubKey']['addresses'][0] + assert 1 == bitcoind.rpc.gettxout(closetxid[idindex[n]], output_num1)['confirmations'] + + @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): """Test penalty transaction with an incoming HTLC"""