rbf-test: confirm that rbf'd inflight is opened and closed as expected

We weren't testing that a non-tip inflight would get opened correctly.
Until now, that is.
This commit is contained in:
niftynei
2021-05-20 16:55:45 -05:00
committed by Rusty Russell
parent b3565fe2ed
commit 9d9fdfdfa6

View File

@@ -865,6 +865,104 @@ def test_rbf_broadcast_close_inflights(node_factory, bitcoind, chainparams):
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_rbf_non_last_mined(node_factory, bitcoind, chainparams):
"""
What happens if a 'non-tip' RBF transaction is mined?
"""
l1, l2 = node_factory.get_nodes(2,
opts={'allow_warning': True,
'may_reconnect': 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()
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']
# Make a second inflight
signed_psbt = run_retry()
l1.rpc.openchannel_signed(chan_id, signed_psbt)
# 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)
# Make a 3rd inflight that won't make it into the mempool
signed_psbt = run_retry()
l1.rpc.openchannel_signed(chan_id, signed_psbt)
l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', None)
l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', None)
# We fetch out our inflights list
inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight']
# l2 goes offline
l2.stop()
# The funding transaction gets mined (should be the 2nd inflight)
bitcoind.generate_block(6, wait_for_mempool=1)
# l2 comes back up
l2.start()
# everybody's got the right things now
l1.daemon.wait_for_log(r'to CHANNELD_NORMAL')
l2.daemon.wait_for_log(r'to CHANNELD_NORMAL')
channel = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])
assert channel['funding_txid'] == inflights[1]['funding_txid']
assert channel['scratch_txid'] == inflights[1]['scratch_txid']
# We delete inflights when the channel is in normal ops
assert 'inflights' not in channel
# l2 stops, again
l2.stop()
# l1 drops to chain.
l1.rpc.close(chan_id, 1)
l1.daemon.wait_for_log('Broadcasting txid {}'.format(channel['scratch_txid']))
# The funding transaction gets mined (should be the 2nd inflight)
bitcoind.generate_block(1, wait_for_mempool=1)
l1.daemon.wait_for_log(r'to ONCHAIN')
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
@pytest.mark.openchannel('v2')
def test_funder_options(node_factory, bitcoind):