2021-02-04 20:17:53 +01:00
|
|
|
from fixtures import * # noqa: F401,F403
|
|
|
|
from fixtures import TEST_NETWORK
|
2021-02-10 22:17:02 +01:00
|
|
|
from pyln.client import RpcError
|
2021-02-04 20:17:53 +01:00
|
|
|
from utils import (
|
|
|
|
only_one, wait_for, sync_blockheight, EXPERIMENTAL_FEATURES
|
|
|
|
)
|
|
|
|
|
2021-02-10 22:17:02 +01:00
|
|
|
import pytest
|
2021-02-04 20:17:53 +01:00
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
|
|
|
def find_next_feerate(node, peer):
|
|
|
|
chan = only_one(only_one(node.rpc.listpeers(peer.info['id'])['peers'])['channels'])
|
|
|
|
return chan['next_feerate']
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_v2_rbf(node_factory, bitcoind, chainparams):
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts=[{'dev-force-features': '+223'},
|
|
|
|
{'dev-force-features': '+223'}])
|
|
|
|
|
|
|
|
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)
|
|
|
|
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')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Check that feerate info is correct
|
|
|
|
info_1 = only_one(only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['channels'])
|
|
|
|
assert info_1['initial_feerate'] == info_1['last_feerate']
|
|
|
|
rate = int(info_1['last_feerate'][:-5])
|
|
|
|
assert int(info_1['next_feerate'][:-5]) == rate + rate // 4
|
|
|
|
assert info_1['next_fee_step'] == 1
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Do the bump
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
assert update['commitments_secured']
|
|
|
|
|
|
|
|
# Check that feerate info has incremented
|
|
|
|
info_2 = only_one(only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['channels'])
|
|
|
|
assert info_1['initial_feerate'] == info_2['initial_feerate']
|
|
|
|
assert info_1['next_feerate'] == info_2['last_feerate']
|
|
|
|
|
|
|
|
rate = int(info_2['last_feerate'][:-5])
|
|
|
|
assert int(info_2['next_feerate'][:-5]) == rate + rate // 4
|
|
|
|
assert info_2['next_fee_step'] == 2
|
|
|
|
|
|
|
|
# Sign our inputs, and continue
|
|
|
|
signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
|
|
|
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
|
|
|
|
|
|
|
bitcoind.generate_block(1)
|
|
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
l1.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
|
|
|
|
# Check that feerate info is gone
|
|
|
|
info_1 = only_one(only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['channels'])
|
|
|
|
assert 'initial_feerate' not in info_1
|
|
|
|
assert 'last_feerate' not in info_1
|
|
|
|
assert 'next_feerate' not in info_1
|
|
|
|
assert 'next_fee_step' not in info_1
|
|
|
|
|
|
|
|
# Shut l2 down, force close the channel.
|
|
|
|
l2.stop()
|
|
|
|
resp = l1.rpc.close(l2.info['id'], unilateraltimeout=1)
|
|
|
|
assert resp['type'] == 'unilateral'
|
|
|
|
l1.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN')
|
|
|
|
l1.daemon.wait_for_log('sendrawtx exit 0')
|
|
|
|
|
2021-02-10 22:17:02 +01:00
|
|
|
|
2021-02-12 00:01:07 +01:00
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_v2_rbf_multi(node_factory, bitcoind, chainparams):
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts=[{'dev-force-features': '+223'},
|
|
|
|
{'dev-force-features': '+223'}])
|
|
|
|
|
|
|
|
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)
|
|
|
|
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')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Do the bump
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
assert update['commitments_secured']
|
|
|
|
|
|
|
|
# Sign our inputs, and continue
|
|
|
|
signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
|
|
|
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF, double the channel amount this time
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount * 2, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Do the bump
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount * 2, initpsbt['psbt'])
|
|
|
|
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
assert update['commitments_secured']
|
|
|
|
|
|
|
|
# Sign our inputs, and continue
|
|
|
|
signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
|
|
|
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
|
|
|
|
|
|
|
bitcoind.generate_block(1)
|
|
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
l1.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
|
|
|
|
|
2021-02-10 22:17:02 +01:00
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_rbf_reconnect_init(node_factory, bitcoind, chainparams):
|
|
|
|
disconnects = ['-WIRE_INIT_RBF',
|
|
|
|
'@WIRE_INIT_RBF',
|
|
|
|
'+WIRE_INIT_RBF']
|
|
|
|
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts=[{'dev-force-features': '+223',
|
|
|
|
'disconnect': disconnects,
|
|
|
|
'may_reconnect': True},
|
|
|
|
{'dev-force-features': '+223',
|
|
|
|
'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)
|
|
|
|
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')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Do the bump!?
|
|
|
|
for d in disconnects:
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
with pytest.raises(RpcError):
|
|
|
|
l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
assert l1.rpc.getpeer(l2.info['id']) is not None
|
|
|
|
|
|
|
|
# This should succeed
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_rbf_reconnect_ack(node_factory, bitcoind, chainparams):
|
|
|
|
disconnects = ['-WIRE_ACK_RBF',
|
|
|
|
'@WIRE_ACK_RBF',
|
|
|
|
'+WIRE_ACK_RBF']
|
|
|
|
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts=[{'dev-force-features': '+223',
|
|
|
|
'may_reconnect': True},
|
|
|
|
{'dev-force-features': '+223',
|
|
|
|
'disconnect': disconnects,
|
|
|
|
'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)
|
|
|
|
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')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Do the bump!?
|
|
|
|
for d in disconnects:
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
with pytest.raises(RpcError):
|
|
|
|
l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
assert l1.rpc.getpeer(l2.info['id']) is not None
|
|
|
|
|
|
|
|
# This should succeed
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
2021-02-11 00:46:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_rbf_reconnect_tx_construct(node_factory, bitcoind, chainparams):
|
|
|
|
disconnects = ['=WIRE_TX_ADD_INPUT', # Initial funding succeeds
|
|
|
|
'-WIRE_TX_ADD_INPUT',
|
|
|
|
'@WIRE_TX_ADD_INPUT',
|
|
|
|
'+WIRE_TX_ADD_INPUT',
|
|
|
|
'-WIRE_TX_ADD_OUTPUT',
|
|
|
|
'@WIRE_TX_ADD_OUTPUT',
|
|
|
|
'+WIRE_TX_ADD_OUTPUT',
|
|
|
|
'-WIRE_TX_COMPLETE',
|
|
|
|
'@WIRE_TX_COMPLETE',
|
|
|
|
'+WIRE_TX_COMPLETE']
|
|
|
|
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts=[{'dev-force-features': '+223',
|
|
|
|
'disconnect': disconnects,
|
|
|
|
'may_reconnect': True},
|
|
|
|
{'dev-force-features': '+223',
|
|
|
|
'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)
|
|
|
|
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')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Run through TX_ADD wires
|
|
|
|
for d in disconnects[1:-3]:
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
with pytest.raises(RpcError):
|
|
|
|
l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
assert l1.rpc.getpeer(l2.info['id']) is not None
|
|
|
|
|
|
|
|
# Now we finish off the completes failure check
|
|
|
|
for d in disconnects[-3:]:
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
with pytest.raises(RpcError):
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
|
|
|
|
# Now we succeed
|
|
|
|
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']
|
2021-02-12 00:01:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_rbf_reconnect_tx_sigs(node_factory, bitcoind, chainparams):
|
|
|
|
disconnects = ['=WIRE_TX_SIGNATURES', # Initial funding succeeds
|
|
|
|
'-WIRE_TX_SIGNATURES', # When we send tx-sigs, RBF
|
|
|
|
'=WIRE_TX_SIGNATURES', # When we reconnect
|
|
|
|
'@WIRE_TX_SIGNATURES', # When we RBF again
|
|
|
|
'=WIRE_TX_SIGNATURES', # When we reconnect
|
|
|
|
'+WIRE_TX_SIGNATURES'] # When we RBF again
|
|
|
|
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts=[{'dev-force-features': '+223',
|
|
|
|
'disconnect': disconnects,
|
|
|
|
'may_reconnect': True,
|
|
|
|
# On reconnects, we dont have cmd
|
|
|
|
# outstanding for the missed sigs
|
|
|
|
# so l1 logs a BROKEN.
|
|
|
|
'allow_broken_log': True},
|
|
|
|
{'dev-force-features': '+223',
|
|
|
|
'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)
|
|
|
|
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('Broadcasting funding tx')
|
|
|
|
l1.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight,
|
|
|
|
prev_utxos, reservedok=True,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
|
|
|
|
# Sign our inputs, and continue
|
|
|
|
signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
|
|
|
|
|
|
|
# First time we error when we send our sigs
|
|
|
|
with pytest.raises(RpcError, match='Owning subdaemon dualopend died'):
|
|
|
|
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
|
|
|
|
|
|
|
# We reconnect and try again. feerate should have bumped
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
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)
|
|
|
|
|
|
|
|
# l2 gets our sigs and broadcasts them
|
|
|
|
l2.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH')
|
|
|
|
l2.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES')
|
|
|
|
l2.daemon.wait_for_log('sendrawtx exit 0')
|
|
|
|
|
|
|
|
# Wait until we've done re-establish, if we try to
|
|
|
|
# RBF again too quickly, it'll fail since they haven't
|
|
|
|
# had time to process our sigs yet
|
|
|
|
l1.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH')
|
|
|
|
l1.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES')
|
|
|
|
|
|
|
|
# Now we initiate the RBF
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
|
|
|
|
# Sign our inputs, and continue
|
|
|
|
signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
|
|
|
|
|
|
|
# Second time we error after we send our sigs
|
|
|
|
with pytest.raises(RpcError, match='Owning subdaemon dualopend died'):
|
|
|
|
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
|
|
|
|
|
|
|
# We reconnect and try again. feerate should have bumped
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
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)
|
|
|
|
|
|
|
|
# l2 gets our sigs and broadcasts them
|
|
|
|
l2.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH')
|
|
|
|
l2.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES')
|
|
|
|
l2.daemon.wait_for_log('sendrawtx exit 0')
|
|
|
|
|
|
|
|
# Wait until we've done re-establish, if we try to
|
|
|
|
# RBF again too quickly, it'll fail since they haven't
|
|
|
|
# had time to process our sigs yet
|
|
|
|
l1.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH')
|
|
|
|
l1.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES')
|
|
|
|
|
|
|
|
# 3rd RBF
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
update = l1.rpc.openchannel_update(chan_id, bump['psbt'])
|
|
|
|
signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt']
|
|
|
|
|
|
|
|
# Third time we error after we send our sigs
|
|
|
|
with pytest.raises(RpcError, match='Owning subdaemon dualopend died'):
|
|
|
|
l1.rpc.openchannel_signed(chan_id, signed_psbt)
|
|
|
|
|
|
|
|
# l2 gets our sigs
|
|
|
|
l2.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES')
|
|
|
|
l2.daemon.wait_for_log('sendrawtx exit 0')
|
|
|
|
|
|
|
|
# mine a block?
|
|
|
|
bitcoind.generate_block(1)
|
|
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
l1.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
|
|
|
|
# Check that they have matching funding txid
|
|
|
|
l1_funding_txid = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['funding_txid']
|
|
|
|
l2_funding_txid = only_one(only_one(l2.rpc.listpeers()['peers'])['channels'])['funding_txid']
|
|
|
|
assert l1_funding_txid == l2_funding_txid
|
2021-02-12 00:14:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
|
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "dual-funding is experimental only")
|
|
|
|
def test_rbf_no_overlap(node_factory, bitcoind, chainparams):
|
|
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
|
|
opts={'dev-force-features': '+223',
|
|
|
|
'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.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)
|
|
|
|
chan_id = res['channel_id']
|
|
|
|
|
|
|
|
# Check that we're waiting for lockin
|
|
|
|
l1.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN')
|
|
|
|
|
|
|
|
next_feerate = find_next_feerate(l1, l2)
|
|
|
|
|
|
|
|
# Initiate an RBF
|
|
|
|
startweight = 42 + 172 # base weight, funding output
|
|
|
|
initpsbt = l1.rpc.fundpsbt(chan_amount, next_feerate, startweight,
|
|
|
|
min_witness_weight=110,
|
|
|
|
excess_as_change=True)
|
|
|
|
|
|
|
|
# Do the bump
|
|
|
|
bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'])
|
|
|
|
|
|
|
|
with pytest.raises(RpcError, match='No overlapping input present.'):
|
|
|
|
l1.rpc.openchannel_update(chan_id, bump['psbt'])
|