From 72c459dd6caf7e9f9628a95d901750c762cad263 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Apr 2018 14:20:58 +0930 Subject: [PATCH] gossipd: keep reaching struct only when we're actively connecting, and don't retry 1. Lifetime of 'struct reaching' now only while we're actively doing connect. 2. Always free after a single attempt: if it's an important peer, retry on a timer. 3. Have a single response message to master, rather than relying on peer_connected on success and other msgs on failure. 4. If we are actively connecting and we get another command for the same id, just increment the counter The result is much simpler in the master daemon, and much nicer for reconnection: if they say to connect they get an immediate response, rather than waiting for 10 retries. Even if it's an important peer, it fires off another reconnect attempt, unless it's actively connecting now. This removes exponential backoff: that's restored in next patch. It also doesn't handle multiple addresses for a single peer. Signed-off-by: Rusty Russell --- gossipd/gossip.c | 200 +++++++++++++++++------------------ gossipd/gossip_wire.csv | 27 +++-- lightningd/connect_control.c | 92 ++++++---------- lightningd/connect_control.h | 10 +- lightningd/gossip_control.c | 11 +- lightningd/peer_control.c | 25 +---- tests/test_lightningd.py | 49 ++++++++- wallet/test/run-wallet.c | 14 --- 8 files changed, 193 insertions(+), 235 deletions(-) diff --git a/gossipd/gossip.c b/gossipd/gossip.c index 850a9805a..fdf968a65 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -53,6 +53,7 @@ #define HSM_FD 3 +/* We put everything in this struct (redundantly) to pass it to timer cb */ struct important_peerid { struct daemon *daemon; @@ -133,14 +134,11 @@ struct reaching { /* The ID of the peer (not necessarily unique, in transit!) */ struct pubkey id; - /* Where I'm reaching to. */ + /* FIXME: Support multiple address. */ struct wireaddr addr; - /* How many times have we attempted to connect? */ - u32 attempts; - - /* Timestamp of the first attempt */ - u32 first_attempt; + /* How many (if any) connect commands are waiting for the result. */ + size_t num_master_responses; }; /* Things we need when we're talking direct to the peer. */ @@ -306,17 +304,24 @@ static struct reaching *find_reaching(struct daemon *daemon, static void reached_peer(struct peer *peer, struct io_conn *conn) { - /* OK, we've reached the peer successfully, stop retrying. */ + /* OK, we've reached the peer successfully, tell everyone. */ struct reaching *r = find_reaching(peer->daemon, &peer->id); + u8 *msg; if (!r) return; - /* Don't free conn with reach. */ - tal_steal(peer->daemon, conn); /* Don't call connect_failed */ io_set_finish(conn, NULL, NULL); + /* Don't free conn with reach */ + tal_steal(peer->daemon, conn); + + /* Tell any connect commands what happened. */ + msg = towire_gossipctl_connect_to_peer_result(r, &r->id, true, ""); + for (size_t i = 0; i < r->num_master_responses; i++) + daemon_conn_send(&peer->daemon->master, msg); + tal_free(r); } @@ -1596,37 +1601,32 @@ static struct io_plan *connection_out(struct io_conn *conn, handshake_out_success, reach); } -static void try_connect(struct reaching *reach); - static void connect_failed(struct io_conn *conn, struct reaching *reach) { - u32 diff = time_now().ts.tv_sec - reach->first_attempt; - reach->attempts++; - - if (!important_peerid_map_get(&reach->daemon->important_peerids, &reach->id) - && reach->attempts >= 10) { - status_info("Failed to connect after %d attempts, giving up " - "after %d seconds", - reach->attempts, diff); - daemon_conn_send( - &reach->daemon->master, - take(towire_gossip_peer_connection_failed( - NULL, &reach->id, diff, reach->attempts, false))); - tal_free(reach); - } else { - unsigned int secs; - - /* Exponential backoff, then every 5 minutes */ - if (reach->attempts < 9) - secs = 1 << reach->attempts; - else - secs = 300; - status_trace("Failed connected out for %s, will try again in %u seconds", - type_to_string(tmpctx, struct pubkey, &reach->id), - secs); - new_reltimer(&reach->daemon->timers, reach, time_from_sec(secs), - try_connect, reach); + u8 *msg; + struct important_peerid *imp; + + /* Tell any connect commands what happened. */ + msg = towire_gossipctl_connect_to_peer_result(reach, &reach->id, + false, strerror(errno)); + for (size_t i = 0; i < reach->num_master_responses; i++) + daemon_conn_send(&reach->daemon->master, msg); + + status_trace("Failed connected out for %s", + type_to_string(tmpctx, struct pubkey, &reach->id)); + + /* If we want to keep trying, do so. */ + imp = important_peerid_map_get(&reach->daemon->important_peerids, + &reach->id); + if (imp) { + /* FIXME: Exponential backoff! */ + status_trace("...will try again in %u seconds", 5); + /* If important_id freed, this will be removed too */ + new_reltimer(&reach->daemon->timers, imp, + time_from_sec(5), retry_important, imp); } + tal_free(reach); + return; } static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach) @@ -1695,34 +1695,50 @@ seed_resolve_addr(const tal_t *ctx, const struct pubkey *id, const u16 port) } } -static void try_connect(struct reaching *reach) +static void try_reach_peer(struct daemon *daemon, const struct pubkey *id, + bool master_needs_response) { struct addrhint *a; int fd; + struct reaching *reach; + u8 *msg; + struct peer *peer = find_peer(daemon, id); - /* Already succeeded somehow? */ - if (find_peer(reach->daemon, &reach->id)) { - status_trace("Already reached %s, not retrying", - type_to_string(tmpctx, struct pubkey, &reach->id)); - tal_free(reach); + if (peer) { + status_debug("try_reach_peer: have peer %s", + type_to_string(tmpctx, struct pubkey, id)); + if (master_needs_response) { + msg = towire_gossipctl_connect_to_peer_result(NULL, id, + true, + ""); + daemon_conn_send(&daemon->master, take(msg)); + } return; } - a = find_addrhint(reach->daemon, &reach->id); + /* If we're trying to reach it right now, that's OK. */ + reach = find_reaching(daemon, id); + if (reach) { + /* Please tell us too. */ + if (master_needs_response) + reach->num_master_responses++; + return; + } + + a = find_addrhint(daemon, id); if (!a) - a = seed_resolve_addr(reach, &reach->id, 9735); + a = seed_resolve_addr(tmpctx, id, 9735); if (!a) { - status_info("No address known for %s, giving up", - type_to_string(tmpctx, struct pubkey, &reach->id)); - daemon_conn_send( - &reach->daemon->master, - take(towire_gossip_peer_connection_failed( - NULL, &reach->id, - time_now().ts.tv_sec - reach->first_attempt, - reach->attempts, true))); - tal_free(reach); + status_debug("No address known for %s, giving up", + type_to_string(tmpctx, struct pubkey, id)); + if (master_needs_response) { + msg = towire_gossipctl_connect_to_peer_result(NULL, id, + false, + "No address known, giving up"); + daemon_conn_send(&daemon->master, take(msg)); + } return; } @@ -1741,52 +1757,33 @@ static void try_connect(struct reaching *reach) } if (fd < 0) { - status_broken("Can't open %i socket for %s (%s), giving up", - a->addr.type, - type_to_string(tmpctx, struct pubkey, &reach->id), - strerror(errno)); - tal_free(reach); + char *err = tal_fmt(tmpctx, + "Can't open %i socket for %s (%s), giving up", + a->addr.type, + type_to_string(tmpctx, struct pubkey, id), + strerror(errno)); + status_debug("%s", err); + if (master_needs_response) { + msg = towire_gossipctl_connect_to_peer_result(NULL, id, + false, err); + daemon_conn_send(&daemon->master, take(msg)); + } return; } - reach->addr = a->addr; - io_new_conn(reach, fd, conn_init, reach); -} - -/* Returns true if we're already connected. */ -static bool try_reach_peer(struct daemon *daemon, const struct pubkey *id) -{ - struct reaching *reach; - struct peer *peer; - - reach = find_reaching(daemon, id); - if (reach) { - status_trace("try_reach_peer: already trying to reach %s", - type_to_string(tmpctx, struct pubkey, id)); - return false; - } - - /* Master might find out before we do that a peer is dead. */ - peer = find_peer(daemon, id); - if (peer) { - status_trace("reach_peer: have peer %s", - type_to_string(tmpctx, struct pubkey, id)); - return true; - } - + /* Start connecting to it */ reach = tal(daemon, struct reaching); reach->daemon = daemon; reach->id = *id; - reach->first_attempt = time_now().ts.tv_sec; - reach->attempts = 0; + reach->addr = a->addr; + reach->num_master_responses = master_needs_response; list_add_tail(&daemon->reaching, &reach->list); tal_add_destructor(reach, destroy_reaching); - try_connect(reach); - return false; + io_new_conn(reach, fd, conn_init, reach); } -/* Reconnect to peer. */ +/* Called from timer, so needs single-arg declaration */ static void retry_important(struct important_peerid *imp) { #if DEVELOPER @@ -1795,24 +1792,18 @@ static void retry_important(struct important_peerid *imp) if (imp->daemon->no_reconnect) return; #endif - try_reach_peer(imp->daemon, &imp->id); + try_reach_peer(imp->daemon, &imp->id, false); } -static struct io_plan *reach_peer(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +static struct io_plan *connect_to_peer(struct io_conn *conn, + struct daemon *daemon, const u8 *msg) { struct pubkey id; - if (!fromwire_gossipctl_reach_peer(msg, &id)) - master_badmsg(WIRE_GOSSIPCTL_REACH_PEER, msg); - - /* Master can't check this itself, because that's racy. */ - if (try_reach_peer(daemon, &id)) { - daemon_conn_send(&daemon->master, - take(towire_gossip_peer_already_connected(NULL, - &id))); - } + if (!fromwire_gossipctl_connect_to_peer(msg, &id)) + master_badmsg(WIRE_GOSSIPCTL_CONNECT_TO_PEER, msg); + try_reach_peer(daemon, &id, true); return daemon_conn_read_next(conn, &daemon->master); } @@ -2108,8 +2099,8 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIPCTL_HAND_BACK_PEER: return hand_back_peer(conn, daemon, master->msg_in); - case WIRE_GOSSIPCTL_REACH_PEER: - return reach_peer(conn, daemon, master->msg_in); + case WIRE_GOSSIPCTL_CONNECT_TO_PEER: + return connect_to_peer(conn, daemon, master->msg_in); case WIRE_GOSSIPCTL_PEER_ADDRHINT: return addr_hint(conn, daemon, master->msg_in); @@ -2149,8 +2140,7 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIP_PING_REPLY: case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY: case WIRE_GOSSIP_PEER_CONNECTED: - case WIRE_GOSSIP_PEER_ALREADY_CONNECTED: - case WIRE_GOSSIP_PEER_CONNECTION_FAILED: + case WIRE_GOSSIPCTL_CONNECT_TO_PEER_RESULT: case WIRE_GOSSIP_PEER_NONGOSSIP: case WIRE_GOSSIP_GET_UPDATE: case WIRE_GOSSIP_GET_UPDATE_REPLY: diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index 32600c543..b9f48ed6a 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -29,10 +29,18 @@ gossipctl_peer_addrhint,3014 gossipctl_peer_addrhint,,id,struct pubkey gossipctl_peer_addrhint,,addr,struct wireaddr -# Master -> gossipd: connect to a peer. We may get a peer_connected or -# peer_already_connected -gossipctl_reach_peer,3001 -gossipctl_reach_peer,,id,struct pubkey +# Master -> gossipd: connect to a peer. +gossipctl_connect_to_peer,3001 +gossipctl_connect_to_peer,,id,struct pubkey + +# Gossipd->master: result (not a reply since it can be out-of-order, but +# you will get one reply for every request). +gossipctl_connect_to_peer_result,3020 +gossipctl_connect_to_peer_result,,id,struct pubkey +# True it connected. +gossipctl_connect_to_peer_result,,connected,bool +# Otherwise, why we can't reach them. +gossipctl_connect_to_peer_result,,failreason,wirestring # Master -> gossipd: try to always maintain connection to this peer (or not) gossipctl_peer_important,3010 @@ -50,17 +58,6 @@ gossip_peer_connected,,gfeatures,gflen*u8 gossip_peer_connected,,lflen,u16 gossip_peer_connected,,lfeatures,lflen*u8 -# Gossipd -> master: you asked to reach a peer, we already had. -gossip_peer_already_connected,3015 -gossip_peer_already_connected,,id,struct pubkey - -# gossipd -> master: attempted to connect, unsuccessful, gave up -gossip_peer_connection_failed,3020 -gossip_peer_connection_failed,,id,struct pubkey -gossip_peer_connection_failed,,timeout,u32 -gossip_peer_connection_failed,,attempts,u32 -gossip_peer_connection_failed,,addr_unknown,bool - # Gossipd -> master: peer sent non-gossip packet. Two fds: peer and gossip gossip_peer_nongossip,3003 gossip_peer_nongossip,,id,struct pubkey diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index ef213d0fe..e9a3669db 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -28,79 +28,51 @@ static struct connect *new_connect(struct lightningd *ld, struct connect *c = tal(cmd, struct connect); c->id = *id; c->cmd = cmd; - list_add(&ld->connects, &c->list); + list_add_tail(&ld->connects, &c->list); tal_add_destructor(c, destroy_connect); return c; } -void connect_succeeded(struct lightningd *ld, const struct pubkey *id) +/* Finds first command which matches. */ +static struct connect *find_connect(struct lightningd *ld, + const struct pubkey *id) { - struct connect *i, *next; + struct connect *i; - /* Careful! Completing command frees connect. */ - list_for_each_safe(&ld->connects, i, next, list) { - struct json_result *response; - - if (!pubkey_eq(&i->id, id)) - continue; - - response = new_json_result(i->cmd); - json_object_start(response, NULL); - json_add_pubkey(response, "id", id); - json_object_end(response); - command_success(i->cmd, response); - } -} - -void connect_failed(struct lightningd *ld, const struct pubkey *id, - const char *error) -{ - struct connect *i, *next; - - /* Careful! Completing command frees connect. */ - list_for_each_safe(&ld->connects, i, next, list) { + list_for_each(&ld->connects, i, list) { if (pubkey_eq(&i->id, id)) - command_fail(i->cmd, "%s", error); + return i; } + return NULL; } -void peer_connection_failed(struct lightningd *ld, const u8 *msg) +void gossip_connect_result(struct lightningd *ld, const u8 *msg) { struct pubkey id; - u32 attempts, timediff; - bool addr_unknown; - char *error; - - if (!fromwire_gossip_peer_connection_failed(msg, &id, &timediff, - &attempts, &addr_unknown)) - fatal( - "Gossip gave bad GOSSIP_PEER_CONNECTION_FAILED message %s", - tal_hex(msg, msg)); - - if (addr_unknown) { - error = tal_fmt( - msg, "No address known for node %s, please provide one", - type_to_string(msg, struct pubkey, &id)); - } else { - error = tal_fmt(msg, "Could not connect to %s after %d seconds and %d attempts", - type_to_string(msg, struct pubkey, &id), timediff, - attempts); - } - - connect_failed(ld, &id, error); -} + bool connected; + char *err; + struct connect *c; + + if (!fromwire_gossipctl_connect_to_peer_result(tmpctx, msg, + &id, + &connected, + &err)) + fatal("Gossip gave bad GOSSIPCTL_CONNECT_TO_PEER_RESULT message %s", + tal_hex(msg, msg)); -/* Gossipd tells us peer was already connected. */ -void peer_already_connected(struct lightningd *ld, const u8 *msg) -{ - struct pubkey id; - if (!fromwire_gossip_peer_already_connected(msg, &id)) - fatal("Gossip gave bad GOSSIP_PEER_ALREADY_CONNECTED message %s", - tal_hex(msg, msg)); + c = find_connect(ld, &id); + assert(c); - /* If we were waiting for connection, we succeeded. */ - connect_succeeded(ld, &id); + if (connected) { + struct json_result *response = new_json_result(c->cmd); + json_object_start(response, NULL); + json_add_pubkey(response, "id", &id); + json_object_end(response); + command_success(c->cmd, response); + } else { + command_fail(c->cmd, "%s", err); + } } static void json_connect(struct command *cmd, @@ -191,10 +163,10 @@ static void json_connect(struct command *cmd, } /* Now tell it to try reaching it. */ - msg = towire_gossipctl_reach_peer(cmd, &id); + msg = towire_gossipctl_connect_to_peer(NULL, &id); subd_send_msg(cmd->ld->gossip, take(msg)); - /* Leave this here for gossip_peer_connected */ + /* Leave this here for gossip_connect_result */ new_connect(cmd->ld, &id, cmd); command_still_pending(cmd); } diff --git a/lightningd/connect_control.h b/lightningd/connect_control.h index d1b339972..23c8bdf5f 100644 --- a/lightningd/connect_control.h +++ b/lightningd/connect_control.h @@ -5,14 +5,6 @@ struct lightningd; struct pubkey; -void connect_succeeded(struct lightningd *ld, const struct pubkey *id); -void connect_failed(struct lightningd *ld, const struct pubkey *id, - const char *error); - -/* Gossipd was unable to connect to the peer */ -void peer_connection_failed(struct lightningd *ld, const u8 *msg); - -/* This simply means we asked to reach a peer, but we already have it */ -void peer_already_connected(struct lightningd *ld, const u8 *msg); +void gossip_connect_result(struct lightningd *ld, const u8 *msg); #endif /* LIGHTNING_LIGHTNINGD_CONNECT_CONTROL_H */ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 6d62659c7..062833431 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -125,7 +125,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIP_GETPEERS_REQUEST: case WIRE_GOSSIP_PING: case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST: - case WIRE_GOSSIPCTL_REACH_PEER: + case WIRE_GOSSIPCTL_CONNECT_TO_PEER: case WIRE_GOSSIPCTL_HAND_BACK_PEER: case WIRE_GOSSIPCTL_RELEASE_PEER: case WIRE_GOSSIPCTL_PEER_ADDRHINT: @@ -160,12 +160,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) return 2; peer_connected(gossip->ld, msg, fds[0], fds[1]); break; - case WIRE_GOSSIP_PEER_ALREADY_CONNECTED: - peer_already_connected(gossip->ld, msg); - break; - case WIRE_GOSSIP_PEER_CONNECTION_FAILED: - peer_connection_failed(gossip->ld, msg); - break; case WIRE_GOSSIP_PEER_NONGOSSIP: if (tal_count(fds) != 2) return 2; @@ -174,6 +168,9 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIP_GET_TXOUT: get_txout(gossip, msg); break; + case WIRE_GOSSIPCTL_CONNECT_TO_PEER_RESULT: + gossip_connect_result(gossip->ld, msg); + break; } return 0; } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index dc3dc99c0..71752d5dc 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -492,7 +492,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg, peer_start_channeld(channel, &cs, gossip_index, peer_fd, gossip_fd, NULL, true); - goto connected; + return; case CLOSINGD_SIGEXCHANGE: /* Stop any existing daemon, without triggering error @@ -503,26 +503,17 @@ void peer_connected(struct lightningd *ld, const u8 *msg, peer_start_closingd(channel, &cs, gossip_index, peer_fd, gossip_fd, true, NULL); - goto connected; + return; } abort(); } return_to_gossipd: - /* Otherwise, we hand back to gossipd, to continue. */ - msg = towire_gossipctl_hand_back_peer(msg, &id, &cs, gossip_index, NULL); - subd_send_msg(ld->gossip, take(msg)); - subd_send_fd(ld->gossip, peer_fd); - subd_send_fd(ld->gossip, gossip_fd); - -connected: - /* If we were waiting for connection, we succeeded. */ - connect_succeeded(ld, &id); - return; + /* No err, all good. */ + error = NULL; send_error: /* Hand back to gossipd, with an error packet. */ - connect_failed(ld, &id, sanitize_error(msg, error, NULL)); msg = towire_gossipctl_hand_back_peer(msg, &id, &cs, gossip_index, error); subd_send_msg(ld->gossip, take(msg)); @@ -610,7 +601,6 @@ void peer_sent_nongossip(struct lightningd *ld, send_error: /* Hand back to gossipd, with an error packet. */ - connect_failed(ld, id, sanitize_error(tmpctx, error, NULL)); msg = towire_gossipctl_hand_back_peer(ld, id, cs, gossip_index, error); subd_send_msg(ld->gossip, take(msg)); subd_send_fd(ld->gossip, peer_fd); @@ -1068,13 +1058,6 @@ static void json_close(struct command *cmd, subd_send_msg(channel->owner, take(towire_channel_send_shutdown(channel))); } - /* If channel has no owner, it means the peer is disconnected, - * so make a nominal effort to contact it now. - */ - if (!channel->owner) - subd_send_msg(cmd->ld->gossip, - take(towire_gossipctl_reach_peer(NULL, - &channel->peer->id))); /* Register this command for later handling. */ register_close_command(cmd->ld, cmd, channel, timeout, force); diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index dba580231..1155debf8 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -78,7 +78,9 @@ def wait_forget_channels(node): """This node is closing all of its channels, check we are forgetting them """ node.daemon.wait_for_log(r'onchaind complete, forgetting peer') - assert node.rpc.listpeers()['peers'] == [] + # May have reconnected, but should merely be gossiping. + for peer in node.rpc.listpeers()['peers']: + assert peer['state'] == 'GOSSIPING' assert node.db_query("SELECT * FROM channels") == [] @@ -616,6 +618,11 @@ class LightningDTests(BaseLightningDTests): assert len(l1.rpc.listpeers()) == 1 assert len(l2.rpc.listpeers()) == 1 + # Should get reasonable error if unknown addr for peer. + self.assertRaisesRegex(ValueError, + "No address known", + l1.rpc.connect, '032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e') + def test_connect_standard_addr(self): """Test standard node@host:port address """ @@ -635,6 +642,34 @@ class LightningDTests(BaseLightningDTests): # ret = l1.rpc.connect("{}@[::1]:{}".format(l3.info['id'], l3.info['port'])) # assert ret['id'] == l3.info['id'] + def test_reconnect_channel_peers(self): + l1 = self.node_factory.get_node(may_reconnect=True) + l2 = self.node_factory.get_node(may_reconnect=True) + l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + + self.fund_channel(l1, l2, 10**6) + l2.stop() + l2.daemon.start() + + # Should reconnect. + wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'][0]['connected']) + wait_for(lambda: l2.rpc.listpeers(l1.info['id'])['peers'][0]['connected']) + # Connect command should succeed. + l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + + # Stop l2 and wait for l1 to notice. + l2.stop() + wait_for(lambda: not l1.rpc.listpeers(l2.info['id'])['peers'][0]['connected']) + + # Now should fail. + self.assertRaisesRegex(ValueError, + "Connection refused", + l1.rpc.connect, l2.info['id'], 'localhost', l2.info['port']) + + # It should now succeed when it restarts. + l2.daemon.start() + l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + def test_balance(self): l1, l2 = self.connect() @@ -2961,18 +2996,24 @@ class LightningDTests(BaseLightningDTests): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_disconnect(self): - # These should all make us fail, and retry. - # FIXME: Configure short timeout for reconnect! + # These should all make us fail disconnects = ['-WIRE_INIT', '@WIRE_INIT', '+WIRE_INIT'] l1 = self.node_factory.get_node(disconnect=disconnects) l2 = self.node_factory.get_node() + + self.assertRaises(ValueError, l1.rpc.connect, + l2.info['id'], 'localhost', l2.info['port']) + self.assertRaises(ValueError, l1.rpc.connect, + l2.info['id'], 'localhost', l2.info['port']) + self.assertRaises(ValueError, l1.rpc.connect, + l2.info['id'], 'localhost', l2.info['port']) l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) # Should have 3 connect fails. for d in disconnects: - l1.daemon.wait_for_log('Failed connected out for {}, will try again' + l1.daemon.wait_for_log('Failed connected out for {}' .format(l2.info['id'])) # Should still only have one peer! diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index a25938f1b..fd013db3f 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -58,13 +58,6 @@ void command_still_pending(struct command *cmd UNNEEDED) /* Generated stub for command_success */ void command_success(struct command *cmd UNNEEDED, struct json_result *response UNNEEDED) { fprintf(stderr, "command_success called!\n"); abort(); } -/* Generated stub for connect_failed */ -void connect_failed(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED, - const char *error UNNEEDED) -{ fprintf(stderr, "connect_failed called!\n"); abort(); } -/* Generated stub for connect_succeeded */ -void connect_succeeded(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED) -{ fprintf(stderr, "connect_succeeded called!\n"); abort(); } /* Generated stub for derive_basepoints */ bool derive_basepoints(const struct privkey *seed UNNEEDED, struct pubkey *funding_pubkey UNNEEDED, @@ -343,10 +336,6 @@ void peer_start_closingd(struct channel *channel UNNEEDED, bool reconnected UNNEEDED, const u8 *channel_reestablish UNNEEDED) { fprintf(stderr, "peer_start_closingd called!\n"); abort(); } -/* Generated stub for sanitize_error */ -char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED, - struct channel_id *channel_id UNNEEDED) -{ fprintf(stderr, "sanitize_error called!\n"); abort(); } /* Generated stub for subd_release_channel */ void subd_release_channel(struct subd *owner UNNEEDED, void *channel UNNEEDED) { fprintf(stderr, "subd_release_channel called!\n"); abort(); } @@ -394,9 +383,6 @@ u8 *towire_gossipctl_peer_disconnect(const tal_t *ctx UNNEEDED, const struct pub /* Generated stub for towire_gossipctl_peer_important */ u8 *towire_gossipctl_peer_important(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, bool important UNNEEDED) { fprintf(stderr, "towire_gossipctl_peer_important called!\n"); abort(); } -/* Generated stub for towire_gossipctl_reach_peer */ -u8 *towire_gossipctl_reach_peer(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED) -{ fprintf(stderr, "towire_gossipctl_reach_peer called!\n"); abort(); } /* Generated stub for towire_gossip_disable_channel */ u8 *towire_gossip_disable_channel(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED, u8 direction UNNEEDED, bool active UNNEEDED) { fprintf(stderr, "towire_gossip_disable_channel called!\n"); abort(); }