Skip to content

Commit 2520bd5

Browse files
committed
pytest: test withhold parameter to fundchannel_complete.
Signed-off-by: Rusty Russell <[email protected]>
1 parent ead680e commit 2520bd5

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

contrib/pyln-client/pyln/client/lightning.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,13 +847,14 @@ def fundchannel_cancel(self, node_id):
847847
}
848848
return self.call("fundchannel_cancel", payload)
849849

850-
def fundchannel_complete(self, node_id, psbt):
850+
def fundchannel_complete(self, node_id, psbt, withhold=True):
851851
"""
852852
Complete channel establishment with {id}, using {psbt}.
853853
"""
854854
payload = {
855855
"id": node_id,
856856
"psbt": psbt,
857+
"withhold": withhold,
857858
}
858859
return self.call("fundchannel_complete", payload)
859860

tests/test_opening.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2867,3 +2867,79 @@ def test_sendpsbt_crash(bitcoind, node_factory):
28672867
bitcoind.generate_block(1, wait_for_mempool=1)
28682868

28692869
assert l1.daemon.is_in_log('Signed and sent psbt for waiting channel')
2870+
2871+
2872+
@pytest.mark.parametrize("stay_withheld", [True, False])
2873+
@pytest.mark.parametrize("mutual_close", [True, False])
2874+
def test_zeroconf_withhold(node_factory, bitcoind, stay_withheld, mutual_close):
2875+
plugin_path = Path(__file__).parent / "plugins" / "zeroconf-selective.py"
2876+
2877+
l1, l2 = node_factory.get_nodes(2, opts=[{'may_reconnect': True,
2878+
'dev-no-reconnect': None,
2879+
},
2880+
{'plugin': str(plugin_path),
2881+
'zeroconf_allow': '0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518',
2882+
'may_reconnect': True,
2883+
'dev-no-reconnect': None,
2884+
}])
2885+
# Try to open a mindepth=0 channel
2886+
l1.fundwallet(10**7)
2887+
2888+
l1.connect(l2)
2889+
amount = 1000000
2890+
funding_addr = l1.rpc.fundchannel_start(l2.info['id'], f"{amount}sat", mindepth=0)['funding_address']
2891+
2892+
# Create the funding transaction
2893+
psbt = l1.rpc.fundpsbt(amount, "1000perkw", 1000, excess_as_change=True)['psbt']
2894+
psbt = l1.rpc.addpsbtoutput(1000000, psbt, destination=funding_addr)['psbt']
2895+
2896+
# Be sure fundchannel_complete is successful
2897+
assert l1.rpc.fundchannel_complete(l2.info['id'], psbt, withhold=True)['commitments_secured']
2898+
2899+
# It's withheld.
2900+
assert only_one(l1.rpc.listpeerchannels()['channels'])['funding']['withheld'] is True
2901+
2902+
# We can use the channel (once they send an update)
2903+
wait_for(lambda: 'remote' in only_one(l1.rpc.listpeerchannels()['channels'])['updates'])
2904+
l1.rpc.xpay(l2.rpc.invoice(100, "test_zeroconf_withhold", "test_zeroconf_withhold")['bolt11'])
2905+
2906+
# But mempool is empty! No funding tx!
2907+
assert bitcoind.rpc.getrawmempool() == []
2908+
2909+
# Restarting doesn't make it transmit!
2910+
l1.restart()
2911+
assert bitcoind.rpc.getrawmempool() == []
2912+
2913+
if mutual_close:
2914+
l1.connect(l2)
2915+
2916+
if not stay_withheld:
2917+
# sendpsbt marks it as no longer withheld.
2918+
l1.rpc.sendpsbt(l1.rpc.signpsbt(psbt)['signed_psbt'])
2919+
assert only_one(l1.rpc.listpeerchannels()['channels'])['funding']['withheld'] is False
2920+
assert l1.daemon.is_in_log(r'Funding PSBT sent, and stored for rexmit \(was withheld\)')
2921+
wait_for(lambda: len(bitcoind.rpc.getrawmempool()) == 1)
2922+
2923+
if mutual_close:
2924+
ret = l1.rpc.close(l2.info['id'])
2925+
else:
2926+
ret = l1.rpc.close(l2.info['id'], unilateraltimeout=1)
2927+
2928+
if stay_withheld:
2929+
assert ret['txs'] == []
2930+
assert ret['txids'] == []
2931+
assert bitcoind.rpc.getrawmempool() == []
2932+
else:
2933+
assert len(ret['txs']) == 1
2934+
assert len(ret['txids']) == 1
2935+
wait_for(lambda: len(bitcoind.rpc.getrawmempool()) == 2)
2936+
2937+
# If withheld, it's moved to closed immediately.
2938+
if stay_withheld:
2939+
assert l1.rpc.listpeerchannels()['channels'] == []
2940+
assert only_one(l1.rpc.listclosedchannels()['closedchannels'])['funding_withheld'] is True
2941+
else:
2942+
if mutual_close:
2943+
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CLOSINGD_COMPLETE')
2944+
else:
2945+
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'AWAITING_UNILATERAL')

0 commit comments

Comments
 (0)