lightningd: check peers don't leave dangling HTLCs when they die.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-11-10 12:31:10 +10:30
parent e9337820a0
commit 956350e62e
4 changed files with 47 additions and 7 deletions

View File

@ -198,6 +198,8 @@ static void shutdown_subdaemons(struct lightningd *ld)
close(ld->hsm_fd); close(ld->hsm_fd);
subd_shutdown(ld->gossip, 10); subd_shutdown(ld->gossip, 10);
free_htlcs(ld, NULL);
while ((p = list_top(&ld->peers, struct peer, list)) != NULL) while ((p = list_top(&ld->peers, struct peer, list)) != NULL)
tal_free(p); tal_free(p);
} }

View File

@ -90,6 +90,32 @@ static void peer_set_owner(struct peer *peer, struct subd *owner)
static void destroy_peer(struct peer *peer) 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. */ /* Free any old owner still hanging around. */
peer_set_owner(peer, NULL); peer_set_owner(peer, NULL);
list_del_from(&peer->ld->peers, &peer->list); 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"); 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_map_iter outi;
struct htlc_out *hout; struct htlc_out *hout;
@ -1175,25 +1202,31 @@ static void handle_irrevocably_resolved(struct peer *peer, const u8 *msg)
do { do {
deleted = false; 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;
hout = htlc_out_map_next(&peer->ld->htlcs_out, &outi)) { hout = htlc_out_map_next(&ld->htlcs_out, &outi)) {
if (hout->key.peer != peer) if (peer && hout->key.peer != peer)
continue; continue;
tal_free(hout); tal_free(hout);
deleted = true; 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;
hin = htlc_in_map_next(&peer->ld->htlcs_in, &ini)) { hin = htlc_in_map_next(&ld->htlcs_in, &ini)) {
if (hin->key.peer != peer) if (peer && hin->key.peer != peer)
continue; continue;
tal_free(hin); tal_free(hin);
deleted = true; deleted = true;
} }
/* Can skip over elements due to iterating while deleting. */ /* Can skip over elements due to iterating while deleting. */
} while (deleted); } 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. */ /* FIXME: Remove peer from db. */
log_info(peer->log, "onchaind complete, forgetting peer"); log_info(peer->log, "onchaind complete, forgetting peer");

View File

@ -210,4 +210,6 @@ const char *peer_state_name(enum peer_state state);
void peer_set_condition(struct peer *peer, enum peer_state oldstate, void peer_set_condition(struct peer *peer, enum peer_state oldstate,
enum peer_state state); enum peer_state state);
void setup_listeners(struct lightningd *ld); void setup_listeners(struct lightningd *ld);
void free_htlcs(struct lightningd *ld, const struct peer *peer);
#endif /* LIGHTNING_LIGHTNINGD_PEER_CONTROL_H */ #endif /* LIGHTNING_LIGHTNINGD_PEER_CONTROL_H */

View File

@ -19,6 +19,9 @@ int debug_poll(struct pollfd *fds UNNEEDED, nfds_t nfds UNNEEDED, int timeout UN
/* Generated stub for fatal */ /* Generated stub for fatal */
void fatal(const char *fmt UNNEEDED, ...) void fatal(const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "fatal called!\n"); abort(); } { 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 */ /* Generated stub for gossip_init */
void gossip_init(struct lightningd *ld UNNEEDED) void gossip_init(struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "gossip_init called!\n"); abort(); } { fprintf(stderr, "gossip_init called!\n"); abort(); }