mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-06 23:54:22 +01:00
open-rbf: we broadcast all the commitments for a channel when closed
If you drop an rbf'd channel to chain (before any updates have been made) we should drop *all* of the inflights to chain
This commit is contained in:
@@ -790,6 +790,81 @@ def test_rbf_fails_to_broadcast(node_factory, bitcoind, chainparams):
|
||||
assert last_txs['tx']
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
def test_rbf_broadcast_close_inflights(node_factory, bitcoind, chainparams):
|
||||
"""
|
||||
Close a channel before it's mined, and the most recent transaction
|
||||
hasn't made it to the mempool. Should publish all the commitment
|
||||
transactions that we have.
|
||||
"""
|
||||
l1, l2 = node_factory.get_nodes(2,
|
||||
opts={'allow_warning': True})
|
||||
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
amount = 2**24
|
||||
chan_amount = 100000
|
||||
bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01)
|
||||
bitcoind.generate_block(1)
|
||||
# Wait for it to arrive.
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0)
|
||||
|
||||
res = l1.rpc.fundchannel(l2.info['id'], chan_amount, feerate='7500perkw')
|
||||
chan_id = res['channel_id']
|
||||
vins = bitcoind.rpc.decoderawtransaction(res['tx'])['vin']
|
||||
assert(only_one(vins))
|
||||
prev_utxos = ["{}:{}".format(vins[0]['txid'], vins[0]['vout'])]
|
||||
|
||||
# Check that we're waiting for lockin
|
||||
l1.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN')
|
||||
inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight']
|
||||
assert inflights[-1]['funding_txid'] in bitcoind.rpc.getrawmempool()
|
||||
|
||||
# Make it such that l1 and l2 cannot broadcast transactions
|
||||
# (mimics failing to reach the miner with replacement)
|
||||
def censoring_sendrawtx(r):
|
||||
return {'id': r['id'], 'result': {}}
|
||||
|
||||
l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx)
|
||||
l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx)
|
||||
|
||||
def run_retry():
|
||||
startweight = 42 + 173
|
||||
next_feerate = find_next_feerate(l1, l2)
|
||||
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
||||
prev_utxos, reservedok=True,
|
||||
min_witness_weight=110,
|
||||
excess_as_change=True)
|
||||
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
||||
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
||||
assert update['commitments_secured']
|
||||
|
||||
return l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
||||
|
||||
signed_psbt = run_retry()
|
||||
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
||||
inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight']
|
||||
assert inflights[-1]['funding_txid'] not in bitcoind.rpc.getrawmempool()
|
||||
|
||||
cmtmt_txid = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['scratch_txid']
|
||||
assert cmtmt_txid == inflights[-1]['scratch_txid']
|
||||
|
||||
# l2 goes offline
|
||||
l2.stop()
|
||||
|
||||
# l1 drops to chain.
|
||||
l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', None)
|
||||
l1.rpc.close(chan_id, 1)
|
||||
l1.daemon.wait_for_logs(['Broadcasting txid {}'.format(inflights[0]['scratch_txid']),
|
||||
'Broadcasting txid {}'.format(inflights[1]['scratch_txid']),
|
||||
'sendrawtx exit 0',
|
||||
'sendrawtx exit 25'])
|
||||
assert inflights[0]['scratch_txid'] in bitcoind.rpc.getrawmempool()
|
||||
assert inflights[1]['scratch_txid'] not in bitcoind.rpc.getrawmempool()
|
||||
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
def test_funder_options(node_factory, bitcoind):
|
||||
|
||||
Reference in New Issue
Block a user