diff --git a/common/dev_disconnect.c b/common/dev_disconnect.c index 289bd9fde565..2feaf927862e 100644 --- a/common/dev_disconnect.c +++ b/common/dev_disconnect.c @@ -50,20 +50,47 @@ void dev_disconnect_init(int fd) dev_disconnect_fd = fd; } -enum dev_disconnect dev_disconnect(const struct node_id *id, int pkt_type) +enum dev_disconnect_out dev_disconnect_out(const struct node_id *id, int pkt_type) { if (dev_disconnect_fd == -1) - return DEV_DISCONNECT_NORMAL; + return DEV_DISCONNECT_OUT_NORMAL; if (!dev_disconnect_count) next_dev_disconnect(); if (!dev_disconnect_line[0] + || dev_disconnect_line[0] == DEV_DISCONNECT_IN_AFTER_RECV || !streq(peer_wire_name(pkt_type), dev_disconnect_line+1)) - return DEV_DISCONNECT_NORMAL; + return DEV_DISCONNECT_OUT_NORMAL; if (--dev_disconnect_count != 0) { - return DEV_DISCONNECT_NORMAL; + return DEV_DISCONNECT_OUT_NORMAL; + } + + if (lseek(dev_disconnect_fd, dev_disconnect_len+1, SEEK_CUR) < 0) { + err(1, "lseek failure"); + } + + status_peer_debug(id, "dev_disconnect: %s (%s)", + dev_disconnect_line, + peer_wire_name(pkt_type)); + return dev_disconnect_line[0]; +} + +enum dev_disconnect_in dev_disconnect_in(const struct node_id *id, int pkt_type) +{ + if (dev_disconnect_fd == -1) + return DEV_DISCONNECT_IN_NORMAL; + + if (!dev_disconnect_count) + next_dev_disconnect(); + + if (dev_disconnect_line[0] != DEV_DISCONNECT_IN_AFTER_RECV + || !streq(peer_wire_name(pkt_type), dev_disconnect_line+1)) + return DEV_DISCONNECT_IN_NORMAL; + + if (--dev_disconnect_count != 0) { + return DEV_DISCONNECT_IN_NORMAL; } if (lseek(dev_disconnect_fd, dev_disconnect_len+1, SEEK_CUR) < 0) { diff --git a/common/dev_disconnect.h b/common/dev_disconnect.h index 1b28fd30d891..0237cd25fc3e 100644 --- a/common/dev_disconnect.h +++ b/common/dev_disconnect.h @@ -5,23 +5,33 @@ struct node_id; -enum dev_disconnect { +enum dev_disconnect_out { /* Do nothing. */ - DEV_DISCONNECT_NORMAL = '=', + DEV_DISCONNECT_OUT_NORMAL = '=', /* Close connection before sending packet. */ - DEV_DISCONNECT_BEFORE = '-', + DEV_DISCONNECT_OUT_BEFORE = '-', /* Close connection after sending packet. */ - DEV_DISCONNECT_AFTER = '+', + DEV_DISCONNECT_OUT_AFTER = '+', /* Drop message (don't send to peer) */ - DEV_DISCONNECT_DROP = '$', + DEV_DISCONNECT_OUT_DROP = '$', /* Swallow all writes from now on, and do no more reads. */ - DEV_DISCONNECT_BLACKHOLE = '0', + DEV_DISCONNECT_OUT_BLACKHOLE = '0', /* Don't use connection after sending packet, but don't close. */ - DEV_DISCONNECT_DISABLE_AFTER = 'x', + DEV_DISCONNECT_OUT_DISABLE_AFTER = 'x', }; /* Force a close fd before or after a certain packet type */ -enum dev_disconnect dev_disconnect(const struct node_id *id, int pkt_type); +enum dev_disconnect_out dev_disconnect_out(const struct node_id *id, int pkt_type); + +enum dev_disconnect_in { + /* Do nothing. */ + DEV_DISCONNECT_IN_NORMAL = '=', + /* Close connection after receiving packet. */ + DEV_DISCONNECT_IN_AFTER_RECV = '<', +}; + +/* Force a close fd after receiving a certain packet type */ +enum dev_disconnect_in dev_disconnect_in(const struct node_id *id, int pkt_type); /* Make next write on fd fail as if they'd disconnected. */ void dev_sabotage_fd(int fd, bool close_fd); diff --git a/connectd/connectd.c b/connectd/connectd.c index db06054a3cbc..881db38fee10 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -2017,6 +2017,7 @@ static void peer_downgrade(struct daemon *daemon, const u8 *msg) if (!fromwire_connectd_downgrade_peer(msg, &id)) master_badmsg(WIRE_CONNECTD_DOWNGRADE_PEER, msg); + status_peer_debug(&id, "peer_downgrade"); tal_free(important_id_htable_get(daemon->important_ids, &id)); } diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 817994b670ae..227dbe6a9579 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -415,25 +415,25 @@ static struct io_plan *encrypt_and_send(struct peer *peer, { int type = fromwire_peektype(msg); - switch (dev_disconnect(&peer->id, type)) { - case DEV_DISCONNECT_BEFORE: + switch (dev_disconnect_out(&peer->id, type)) { + case DEV_DISCONNECT_OUT_BEFORE: if (taken(msg)) tal_free(msg); return io_close(peer->to_peer); - case DEV_DISCONNECT_AFTER: + case DEV_DISCONNECT_OUT_AFTER: /* Disallow reads from now on */ peer->dev_read_enabled = false; /* Using io_close here can lose the data we're about to send! */ next = io_sock_shutdown_cb; break; - case DEV_DISCONNECT_BLACKHOLE: + case DEV_DISCONNECT_OUT_BLACKHOLE: /* Disable both reads and writes from now on */ peer->dev_read_enabled = false; peer->dev_writes_enabled = talz(peer, u32); break; - case DEV_DISCONNECT_NORMAL: + case DEV_DISCONNECT_OUT_NORMAL: break; - case DEV_DISCONNECT_DROP: + case DEV_DISCONNECT_OUT_DROP: /* Drop this message and continue */ if (taken(msg)) tal_free(msg); @@ -441,7 +441,7 @@ static struct io_plan *encrypt_and_send(struct peer *peer, io_wake(&peer->subds); return msg_queue_wait(peer->to_peer, peer->peer_outq, next, peer); - case DEV_DISCONNECT_DISABLE_AFTER: + case DEV_DISCONNECT_OUT_DISABLE_AFTER: peer->dev_read_enabled = false; peer->dev_writes_enabled = tal(peer, u32); *peer->dev_writes_enabled = 1; @@ -1136,6 +1136,13 @@ static struct subd *new_subd(struct peer *peer, return subd; } +static struct io_plan *close_peer_dev_disconnect(struct io_conn *peer_conn, + struct peer *peer) +{ + assert(peer->to_peer == peer_conn); + return io_close_cb(peer_conn, peer); +} + static struct io_plan *read_hdr_from_peer(struct io_conn *peer_conn, struct peer *peer); static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, @@ -1145,7 +1152,8 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, struct channel_id channel_id; struct subd *subd; enum peer_wire type; - + struct io_plan *(*next_read)(struct io_conn *peer_conn, + struct peer *peer) = read_hdr_from_peer; decrypted = cryptomsg_decrypt_body(tmpctx, &peer->cs, peer->peer_in); @@ -1162,16 +1170,24 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, if (!peer->dev_read_enabled) return read_hdr_from_peer(peer_conn, peer); + switch (dev_disconnect_in(&peer->id, type)) { + case DEV_DISCONNECT_IN_NORMAL: + break; + case DEV_DISCONNECT_IN_AFTER_RECV: + next_read = close_peer_dev_disconnect; + break; + } + /* We got something! */ peer->last_recv_time = time_now(); /* Don't process packets while we're closing */ if (peer->draining) - return read_hdr_from_peer(peer_conn, peer); + return next_read(peer_conn, peer); /* If we swallow this, just try again. */ if (handle_message_locally(peer, decrypted)) - return read_hdr_from_peer(peer_conn, peer); + return next_read(peer_conn, peer); /* After this we should be able to match to subd by channel_id */ if (!extract_channel_id(decrypted, &channel_id)) { @@ -1186,7 +1202,7 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, "Received %s: %s", peer_wire_name(type), desc); if (type == WIRE_WARNING) - return read_hdr_from_peer(peer_conn, peer); + return next_read(peer_conn, peer); return io_close(peer_conn); } @@ -1194,7 +1210,7 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, send_warning(peer, "Unexpected message %s: %s", peer_wire_name(type), tal_hex(tmpctx, decrypted)); - return read_hdr_from_peer(peer_conn, peer); + return next_read(peer_conn, peer); } /* If we don't find a subdaemon for this, create a new one. */ @@ -1237,7 +1253,7 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, } /* Wait for them to wake us */ - return io_wait(peer_conn, &peer->peer_in, read_hdr_from_peer, peer); + return io_wait(peer_conn, &peer->peer_in, next_read, peer); } static struct io_plan *read_body_from_peer(struct io_conn *peer_conn, diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index 63b3ddb8da6f..b0a29549caba 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -61,6 +61,13 @@ static struct io_plan *peer_init_received(struct io_conn *conn, status_peer_io(LOG_IO_IN, &peer->id, msg); + switch (dev_disconnect_in(&peer->id, fromwire_peektype(msg))) { + case DEV_DISCONNECT_IN_NORMAL: + break; + case DEV_DISCONNECT_IN_AFTER_RECV: + return io_close(conn); + } + /* BOLT #1: * * A receiving node: @@ -280,21 +287,21 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg)); next = read_init; - switch (dev_disconnect(&peer->id, WIRE_INIT)) { - case DEV_DISCONNECT_BEFORE: + switch (dev_disconnect_out(&peer->id, WIRE_INIT)) { + case DEV_DISCONNECT_OUT_BEFORE: dev_sabotage_fd(io_conn_fd(conn), true); break; - case DEV_DISCONNECT_AFTER: + case DEV_DISCONNECT_OUT_AFTER: next = dev_peer_write_postclose; break; - case DEV_DISCONNECT_BLACKHOLE: + case DEV_DISCONNECT_OUT_BLACKHOLE: status_failed(STATUS_FAIL_INTERNAL_ERROR, "Blackhole not supported during handshake"); break; - case DEV_DISCONNECT_NORMAL: - case DEV_DISCONNECT_DROP: + case DEV_DISCONNECT_OUT_NORMAL: + case DEV_DISCONNECT_OUT_DROP: break; - case DEV_DISCONNECT_DISABLE_AFTER: + case DEV_DISCONNECT_OUT_DISABLE_AFTER: next = dev_peer_write_post_sabotage; break; } diff --git a/contrib/msggen/msggen/schema.json b/contrib/msggen/msggen/schema.json index 766af8fc22a5..048f9f928c57 100644 --- a/contrib/msggen/msggen/schema.json +++ b/contrib/msggen/msggen/schema.json @@ -20552,6 +20552,10 @@ "value_int": 3, "source": "cmdline" }, + "dev-crash-after": { + "value_str": "3600", + "source": "cmdline" + }, "dev-fail-on-subdaemon-fail": { "set": true, "source": "cmdline" diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 41132cf995ca..9acb85fcad54 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -56,6 +56,7 @@ struct io_conn { static struct secret notsosecret; static bool no_gossip = false, all_gossip = false; static unsigned long max_messages = -1UL; +static u16 *accept_messages = NULL; /* Empty stubs to make us compile */ void status_peer_io(enum log_level iodir, @@ -101,6 +102,18 @@ bool is_unknown_msg_discardable(const u8 *cursor) return false; } +static bool accept_message(const u8 *msg) +{ + u16 type = fromwire_peektype(msg); + if (!accept_messages) + return true; + for (size_t i = 0; i < tal_count(accept_messages); i++) { + if (type == accept_messages[i]) + return true; + } + return false; +} + static struct io_plan *simple_write(struct io_conn *conn, const void *data, size_t len, struct io_plan *(*next)(struct io_conn *, void *), @@ -240,6 +253,10 @@ static struct io_plan *handshake_success(struct io_conn *conn, msg = sync_crypto_read(NULL, peer_fd, cs); if (!msg) err(1, "Reading msg"); + if (!accept_message(msg)) { + tal_free(msg); + continue; + } if (hex) { printf("%s\n", tal_hex(msg, msg)); } else { @@ -248,8 +265,8 @@ static struct io_plan *handshake_success(struct io_conn *conn, || !write_all(STDOUT_FILENO, msg, tal_bytelen(msg))) err(1, "Writing out msg"); } - tal_free(msg); --max_messages; + tal_free(msg); } } @@ -284,6 +301,15 @@ static char *opt_set_features(const char *arg, u8 **features) return NULL; } +static char *opt_set_filter(const char *arg, u16 **accept) +{ + char **elems = tal_strsplit(tmpctx, arg, ",", STR_EMPTY_OK); + *accept = tal_arr(NULL, u16, tal_count(elems)-1); + for (size_t i = 0; elems[i]; i++) + (*accept)[i] = atoi(elems[i]); + return NULL; +} + int main(int argc, char *argv[]) { struct io_conn *conn = tal(NULL, struct io_conn); @@ -306,6 +332,8 @@ int main(int argc, char *argv[]) "Stream complete gossip history at start"); opt_register_noarg("--no-gossip", opt_set_bool, &no_gossip, "Suppress all gossip at start"); + opt_register_arg("--filter", opt_set_filter, NULL, &accept_messages, + "Only process these message types"); opt_register_arg("--max-messages", opt_set_ulongval, opt_show_ulongval, &max_messages, "Terminate after reading this many messages"); diff --git a/doc/schemas/lightning-listconfigs.json b/doc/schemas/lightning-listconfigs.json index 260dea4c9e87..f96463d950df 100644 --- a/doc/schemas/lightning-listconfigs.json +++ b/doc/schemas/lightning-listconfigs.json @@ -2678,6 +2678,10 @@ "value_int": 3, "source": "cmdline" }, + "dev-crash-after": { + "value_str": "3600", + "source": "cmdline" + }, "dev-fail-on-subdaemon-fail": { "set": true, "source": "cmdline" diff --git a/gossipd/gossmap_manage.c b/gossipd/gossmap_manage.c index 596d200df3db..cebcf6bcd3ba 100644 --- a/gossipd/gossmap_manage.c +++ b/gossipd/gossmap_manage.c @@ -320,15 +320,15 @@ static void remove_channel(struct gossmap_manage *gm, } } +/* If we don't know, we assume it's good */ static u32 get_timestamp(struct gossmap *gossmap, const struct gossmap_chan *chan, int dir) { u32 timestamp; - /* 0 is sufficient for our needs */ if (!gossmap_chan_set(chan, dir)) - return 0; + return UINT32_MAX; gossmap_chan_get_update_details(gossmap, chan, dir, ×tamp, diff --git a/lightningd/options.c b/lightningd/options.c index 643e0063e6f0..147592a24e53 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -811,6 +811,31 @@ static char *opt_ignore(void *unused) return NULL; } +static void handle_alarm(int sig) +{ + abort(); +} + +static char *opt_set_crash_timeout(const char *arg, struct lightningd *ld) +{ + struct sigaction act; + u32 time; + char *errstr = opt_set_u32(arg, &time); + if (errstr) + return errstr; + + /* In case we're *REALLY* stuck, use alarm() */ + memset(&act, 0, sizeof(act)); + act.sa_handler = handle_alarm; + act.sa_flags = 0; + + if (sigaction(SIGALRM, &act, NULL) != 0) + err(1, "Setting up SIGARLM handler"); + + alarm(time); + return NULL; +} + static void dev_register_opts(struct lightningd *ld) { /* We might want to debug plugins, which are started before normal @@ -978,6 +1003,10 @@ static void dev_register_opts(struct lightningd *ld) opt_set_u32, opt_show_u32, &ld->dev_low_prio_anchor_blocks, "How many blocks to aim for low-priority anchor closes (default: 2016)"); + clnopt_witharg("--dev-crash-after", OPT_DEV, + opt_set_crash_timeout, NULL, + ld, + "Crash if we are still going after this long."); /* This is handled directly in daemon_developer_mode(), so we ignore it here */ clnopt_noarg("--dev-debug-self", OPT_DEV, opt_ignore, @@ -2219,6 +2248,7 @@ bool is_known_opt_cb_arg(char *(*cb_arg)(const char *, void *)) || cb_arg == (void *)opt_add_accept_htlc_tlv || cb_arg == (void *)opt_set_codex32_or_hex || cb_arg == (void *)opt_subd_dev_disconnect + || cb_arg == (void *)opt_set_crash_timeout || cb_arg == (void *)opt_add_api_beg || cb_arg == (void *)opt_force_featureset || cb_arg == (void *)opt_force_privkey diff --git a/tests/fixtures.py b/tests/fixtures.py index ea23f10ad0a9..1e0334afe27a 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -18,6 +18,9 @@ class LightningNode(utils.LightningNode): def __init__(self, *args, **kwargs): utils.LightningNode.__init__(self, *args, **kwargs) + # This is a recent innovation, and we don't want to nail pyln-testing to this version. + self.daemon.opts['dev-crash-after'] = 3600 + # We have some valgrind suppressions in the `tests/` # directory, so we can add these to the valgrind configuration # (not generally true when running pyln-testing, hence why diff --git a/tests/test_closing.py b/tests/test_closing.py index 26f1148e38a0..6fed91de54b4 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -4168,7 +4168,7 @@ def test_onchain_reestablish_reply(node_factory, bitcoind, executor): # Then we get the error, close. l2.daemon.wait_for_log("peer_in WIRE_ERROR") - assert only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])['state'] == 'AWAITING_UNILATERAL' + wait_for(lambda: only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])['state'] == 'AWAITING_UNILATERAL') # Mine it now so we don't confuse the code below. bitcoind.generate_block(1, wait_for_mempool=1) @@ -4239,7 +4239,8 @@ def censoring_sendrawtx(r): height = bitcoind.rpc.getblockchaininfo()['blocks'] l1.daemon.wait_for_log(r"Low-priority anchorspend aiming for block {} \(feerate 7458\)".format(height + 13)) - l1.daemon.wait_for_log(r"Anchorspend for local commit tx fee 12335sat \(w=714\), commit_tx fee 4545sat \(w=768\): package feerate 11390 perkw") + # Can be out-by-one (short sig)! + l1.daemon.wait_for_log(r"Anchorspend for local commit tx fee (12335|12328)sat \(w=714\), commit_tx fee 4545sat \(w=76[78]\): package feerate 1139[02] perkw") assert not l1.daemon.is_in_log("Low-priority anchorspend aiming for block {}".format(height + 12)) bitcoind.generate_block(1) diff --git a/tests/test_connection.py b/tests/test_connection.py index 9f4d12c4476f..d5c85c2498cb 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -21,6 +21,7 @@ import time import unittest import websocket +import signal import ssl @@ -653,13 +654,12 @@ def test_disconnect_half_signed_v2(node_factory): @pytest.mark.openchannel('v2') def test_reconnect_signed(node_factory): # This will fail *after* both sides consider channel opening. - disconnects = ['+WIRE_FUNDING_SIGNED'] + disconnects = [' 3 - # Remove timestamp filter, since timestamp will change! - out2 = [m for m in out2 if not m.startswith(b'0109')] - # Contents should be identical (once uniquified, since each # doubles-up on its own gossip) assert set(out1) == set(out2) @@ -2121,15 +2116,14 @@ def test_gossip_throttle(node_factory, bitcoind, chainparams): '--no-gossip', '--hex', '--network={}'.format(TEST_NETWORK), - '--max-messages={}'.format(expected + 1), + '--filter=256,257,258', + '--max-messages={}'.format(expected), '{}@localhost:{}'.format(l1.info['id'], l1.port), query], check=True, timeout=TIMEOUT, stdout=subprocess.PIPE).stdout.split() time_fast = time.time() - start_fast assert time_fast < 2 - # Ignore gossip_timestamp_filter and reply_short_channel_ids_end - out3 = [m for m in out3 if not m.startswith(b'0109') and not m.startswith(b'0106')] assert set(out1) == set(out3) start_slow = time.time() @@ -2137,6 +2131,7 @@ def test_gossip_throttle(node_factory, bitcoind, chainparams): '--no-gossip', '--hex', '--network={}'.format(TEST_NETWORK), + '--filter=256,257,258', '--max-messages={}'.format(expected), '{}@localhost:{}'.format(l4.info['id'], l4.port), query], @@ -2144,7 +2139,6 @@ def test_gossip_throttle(node_factory, bitcoind, chainparams): timeout=TIMEOUT, stdout=subprocess.PIPE).stdout.split() time_slow = time.time() - start_slow assert time_slow > 3 - out4 = [m for m in out4 if not m.startswith(b'0109')] assert set(out2) == set(out4) diff --git a/tests/test_opening.py b/tests/test_opening.py index af9920404e5e..7346c7283779 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -944,7 +944,7 @@ def test_rbf_reconnect_tx_construct(node_factory, bitcoind, chainparams): l2.daemon.wait_for_logs([r'Got dualopend reestablish', r'No commitment, not sending our sigs', # This is a BROKEN log, it's expected! - r'dualopend daemon died before signed PSBT returned']) + r'dualopend daemon died before signed PSBT returned|dualopend: Owning subdaemon dualopend died']) # We don't have the commtiments yet, there's no scratch_txid inflights = only_one(l1.rpc.listpeerchannels()['channels'])['inflight'] diff --git a/tests/test_splicing_disconnect.py b/tests/test_splicing_disconnect.py index e4553d425ffa..fd3c09fb35dd 100644 --- a/tests/test_splicing_disconnect.py +++ b/tests/test_splicing_disconnect.py @@ -70,8 +70,14 @@ def test_splice_disconnect_sig(node_factory, bitcoind): @pytest.mark.openchannel('v2') @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') def test_splice_disconnect_commit(node_factory, bitcoind, executor): - l1 = node_factory.get_node(options={'experimental-splicing': None}, may_reconnect=True) - l2 = node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED'], + l1 = node_factory.get_node(options={'experimental-splicing': None, 'dev-no-reconnect': None}, + may_reconnect=True) + # Note: for dual-fund, there's a COMMITMENT_SIGNED for the initial tx, before splicing! + if EXPERIMENTAL_DUAL_FUND: + disconnects = ['+WIRE_COMMITMENT_SIGNED*2'] + else: + disconnects = ['+WIRE_COMMITMENT_SIGNED'] + l2 = node_factory.get_node(disconnect=disconnects, options={'experimental-splicing': None, 'dev-no-reconnect': None}, may_reconnect=True) l1.openchannel(l2, 1000000) @@ -91,15 +97,13 @@ def test_splice_disconnect_commit(node_factory, bitcoind, executor): l2.daemon.wait_for_log(r'dev_disconnect: \+WIRE_COMMITMENT_SIGNED') - print("Killing l2 without sending WIRE_COMMITMENT_SIGNED") - l2.daemon.kill() + l1.daemon.kill() - # Restart l1, without disconnect stuff. - del l2.daemon.opts['dev-no-reconnect'] - del l2.daemon.opts['dev-disconnect'] + # Restart l1, should reconnect + del l1.daemon.opts['dev-no-reconnect'] # Should reconnect, and reestablish the splice. - l2.start() + l1.start() # Splice should be abandoned via tx_abort diff --git a/tests/test_xpay.py b/tests/test_xpay.py index f50aedd8a898..ac8ab95847d8 100644 --- a/tests/test_xpay.py +++ b/tests/test_xpay.py @@ -494,6 +494,7 @@ def test_xpay_preapprove(node_factory): @unittest.skipIf(TEST_NETWORK != 'regtest', 'too dusty on elements') +@pytest.mark.slow_test def test_xpay_maxfee(node_factory, bitcoind, chainparams): """Test which shows that we don't excees maxfee""" outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-')