diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 38e383e93..de918c1d9 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1373,6 +1373,7 @@ static void send_funding_tx(struct channel *channel, { struct lightningd *ld = channel->peer->ld; struct channel_send *cs; + struct bitcoin_txid txid; cs = tal(channel, struct channel_send); cs->channel = channel; @@ -1386,8 +1387,10 @@ static void send_funding_tx(struct channel *channel, tal_wally_end(tal_steal(cs, cs->wtx)); } + wally_txid(wtx, &txid); log_debug(channel->log, - "Broadcasting funding tx for channel %s. %s", + "Broadcasting funding tx %s for channel %s. %s", + type_to_string(tmpctx, struct bitcoin_txid, &txid), type_to_string(tmpctx, struct channel_id, &channel->cid), type_to_string(tmpctx, struct wally_tx, cs->wtx)); diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 0860b2b2d..18ea4598e 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -739,10 +739,12 @@ static char *check_balances(const tal_t *ctx, if (!amount_sat_greater_eq(initiator_diff, initiator_fee)) { return tal_fmt(ctx, - "initiator fee %s not covered %s", + "initiator fee %s (%zux%d) not covered %s", type_to_string(ctx, struct amount_sat, &initiator_fee), + initiator_weight, + feerate_per_kw_funding, type_to_string(ctx, struct amount_sat, &initiator_diff)); diff --git a/tests/test_opening.py b/tests/test_opening.py index 7e273c36f..30b8e758f 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1,9 +1,11 @@ from fixtures import * # noqa: F401,F403 from fixtures import TEST_NETWORK +from pyln.client import RpcError from utils import ( only_one, wait_for, sync_blockheight, EXPERIMENTAL_FEATURES ) +import pytest import unittest @@ -89,3 +91,106 @@ def test_v2_rbf(node_factory, bitcoind, chainparams): l1.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN') l1.daemon.wait_for_log('sendrawtx exit 0') + +@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'])