diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index f14224aa1..e7562d1f9 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -198,6 +198,8 @@ static void shutdown_subdaemons(struct lightningd *ld) close(ld->hsm_fd); subd_shutdown(ld->gossip, 10); + free_htlcs(ld, NULL); + while ((p = list_top(&ld->peers, struct peer, list)) != NULL) tal_free(p); } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 035a710f3..f8c9f2931 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -90,6 +90,32 @@ static void peer_set_owner(struct peer *peer, struct subd *owner) static void destroy_peer(struct peer *peer) { + /* Must not have any HTLCs! */ + struct htlc_out_map_iter outi; + struct htlc_out *hout; + struct htlc_in_map_iter ini; + struct htlc_in *hin; + + for (hout = htlc_out_map_first(&peer->ld->htlcs_out, &outi); + hout; + hout = htlc_out_map_next(&peer->ld->htlcs_out, &outi)) { + if (hout->key.peer != peer) + continue; + fatal("Freeing peer %s has hout %s", + peer_state_name(peer->state), + htlc_state_name(hout->hstate)); + } + + for (hin = htlc_in_map_first(&peer->ld->htlcs_in, &ini); + hin; + hin = htlc_in_map_next(&peer->ld->htlcs_in, &ini)) { + if (hin->key.peer != peer) + continue; + fatal("Freeing peer %s has hin %s", + peer_state_name(peer->state), + htlc_state_name(hin->hstate)); + } + /* Free any old owner still hanging around. */ peer_set_owner(peer, NULL); list_del_from(&peer->ld->peers, &peer->list); @@ -1163,7 +1189,8 @@ static void handle_onchain_htlc_timeout(struct peer *peer, const u8 *msg) onchain_failed_our_htlc(peer, &htlc, "timed out"); } -static void handle_irrevocably_resolved(struct peer *peer, const u8 *msg) +/* If peer is NULL, free them all (for shutdown) */ +void free_htlcs(struct lightningd *ld, const struct peer *peer) { struct htlc_out_map_iter outi; struct htlc_out *hout; @@ -1175,25 +1202,31 @@ static void handle_irrevocably_resolved(struct peer *peer, const u8 *msg) do { deleted = false; - for (hout = htlc_out_map_first(&peer->ld->htlcs_out, &outi); + for (hout = htlc_out_map_first(&ld->htlcs_out, &outi); hout; - hout = htlc_out_map_next(&peer->ld->htlcs_out, &outi)) { - if (hout->key.peer != peer) + hout = htlc_out_map_next(&ld->htlcs_out, &outi)) { + if (peer && hout->key.peer != peer) continue; tal_free(hout); deleted = true; } - for (hin = htlc_in_map_first(&peer->ld->htlcs_in, &ini); + for (hin = htlc_in_map_first(&ld->htlcs_in, &ini); hin; - hin = htlc_in_map_next(&peer->ld->htlcs_in, &ini)) { - if (hin->key.peer != peer) + hin = htlc_in_map_next(&ld->htlcs_in, &ini)) { + if (peer && hin->key.peer != peer) continue; tal_free(hin); deleted = true; } /* Can skip over elements due to iterating while deleting. */ } while (deleted); +} + +static void handle_irrevocably_resolved(struct peer *peer, const u8 *msg) +{ + /* FIXME: Implement check_htlcs to ensure no dangling hout->in ptrs! */ + free_htlcs(peer->ld, peer); /* FIXME: Remove peer from db. */ log_info(peer->log, "onchaind complete, forgetting peer"); diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 4025d06e6..58038172e 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -210,4 +210,6 @@ const char *peer_state_name(enum peer_state state); void peer_set_condition(struct peer *peer, enum peer_state oldstate, enum peer_state state); void setup_listeners(struct lightningd *ld); + +void free_htlcs(struct lightningd *ld, const struct peer *peer); #endif /* LIGHTNING_LIGHTNINGD_PEER_CONTROL_H */ diff --git a/lightningd/test/run-find_my_path.c b/lightningd/test/run-find_my_path.c index 001dd9f2d..559478eb9 100644 --- a/lightningd/test/run-find_my_path.c +++ b/lightningd/test/run-find_my_path.c @@ -19,6 +19,9 @@ int debug_poll(struct pollfd *fds UNNEEDED, nfds_t nfds UNNEEDED, int timeout UN /* Generated stub for fatal */ void fatal(const char *fmt UNNEEDED, ...) { fprintf(stderr, "fatal called!\n"); abort(); } +/* Generated stub for free_htlcs */ +void free_htlcs(struct lightningd *ld UNNEEDED, const struct peer *peer UNNEEDED) +{ fprintf(stderr, "free_htlcs called!\n"); abort(); } /* Generated stub for gossip_init */ void gossip_init(struct lightningd *ld UNNEEDED) { fprintf(stderr, "gossip_init called!\n"); abort(); }