From fa8458c00a61764d5b50ce8aa6d95878af2a2235 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 31 Oct 2023 18:07:15 -0500 Subject: [PATCH] dualfund: add test to make sure that tx-sigs sent before commitment results in an error. --- common/dev_disconnect.c | 3 ++- common/dev_disconnect.h | 2 ++ connectd/multiplex.c | 8 ++++++++ connectd/peer_exchange_initmsg.c | 1 + openingd/dualopend.c | 1 - tests/test_opening.py | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/common/dev_disconnect.c b/common/dev_disconnect.c index ce5eb15754bc..289bd9fde565 100644 --- a/common/dev_disconnect.c +++ b/common/dev_disconnect.c @@ -70,7 +70,8 @@ enum dev_disconnect dev_disconnect(const struct node_id *id, int pkt_type) err(1, "lseek failure"); } - status_peer_debug(id, "dev_disconnect: %s (%s)", dev_disconnect_line, + status_peer_debug(id, "dev_disconnect: %s (%s)", + dev_disconnect_line, peer_wire_name(pkt_type)); return dev_disconnect_line[0]; } diff --git a/common/dev_disconnect.h b/common/dev_disconnect.h index bc434514ce98..1b28fd30d891 100644 --- a/common/dev_disconnect.h +++ b/common/dev_disconnect.h @@ -12,6 +12,8 @@ enum dev_disconnect { DEV_DISCONNECT_BEFORE = '-', /* Close connection after sending packet. */ DEV_DISCONNECT_AFTER = '+', + /* Drop message (don't send to peer) */ + DEV_DISCONNECT_DROP = '$', /* Swallow all writes from now on, and do no more reads. */ DEV_DISCONNECT_BLACKHOLE = '0', /* Don't use connection after sending packet, but don't close. */ diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 86e9c4b5afd9..a3b9e2d08258 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -446,6 +446,14 @@ static struct io_plan *encrypt_and_send(struct peer *peer, break; case DEV_DISCONNECT_NORMAL: break; + case DEV_DISCONNECT_DROP: + /* Drop this message and continue */ + if (taken(msg)) + tal_free(msg); + /* Tell them to read again, */ + io_wake(&peer->subds); + return msg_queue_wait(peer->to_peer, peer->peer_outq, + next, peer); case DEV_DISCONNECT_DISABLE_AFTER: peer->dev_read_enabled = false; peer->dev_writes_enabled = tal(peer, u32); diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index b87f8a291680..bef289ad3c52 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -288,6 +288,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, "Blackhole not supported during handshake"); break; case DEV_DISCONNECT_NORMAL: + case DEV_DISCONNECT_DROP: break; case DEV_DISCONNECT_DISABLE_AFTER: next = dev_peer_write_post_sabotage; diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 2997581d0116..5a2311874743 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1628,7 +1628,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) case WIRE_TX_SIGNATURES: /* We can get these when we restart and immediately * startup an RBF */ - handle_tx_sigs(state, msg); continue; case WIRE_CHANNEL_READY: diff --git a/tests/test_opening.py b/tests/test_opening.py index 3d92e0631318..d35782020172 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -216,6 +216,38 @@ def test_v2_open_sigs_reconnect_1(node_factory, bitcoind): l2.daemon.wait_for_log(r'to CHANNELD_NORMAL') +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.xfail +@pytest.mark.openchannel('v2') +def test_v2_open_sigs_out_of_order(node_factory, bitcoind): + """ Test what happens if the tx-sigs get sent "before" commitment signed """ + disconnects = ['$WIRE_COMMITMENT_SIGNED'] + + l1, l2 = node_factory.get_nodes(2, + opts=[{}, + {'disconnect': disconnects}]) + + 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) + + # Fund the channel, should error because L2 doesn't see our commitment-signed + # so they think we've sent things out of order + with pytest.raises(RpcError, match='tx_signatures sent before commitment sigs'): + l1.rpc.fundchannel(l2.info['id'], chan_amount) + + # L1 should remove the in-progress channel + wait_for(lambda: l1.rpc.listpeerchannels()['channels'] == []) + # L2 should fail it to chain + l2.daemon.wait_for_logs([r'to AWAITING_UNILATERAL', + # We can't broadcast this, we don't have sigs for funding + 'sendrawtx exit 25']) + + @pytest.mark.openchannel('v2') def test_v2_fail_second(node_factory, bitcoind): """ Open a channel succeeds; opening a second channel