diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index e4b2aa33d..0b69dc7e3 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -180,7 +180,7 @@ static void peer_disable_channels(struct daemon *daemon, struct node *node) for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { if (node_id_eq(&other_node(node, c)->id, &daemon->id)) - c->local_disabled = true; + local_disable_chan(daemon->rstate, c); } } @@ -1371,19 +1371,21 @@ static void maybe_update_local_channel(struct daemon *daemon, struct chan *chan, int direction) { const struct half_chan *hc = &chan->half[direction]; + bool local_disabled; /* Don't generate a channel_update for an uninitialized channel. */ if (!hc->channel_update) return; /* Nothing to update? */ + local_disabled = is_chan_local_disabled(daemon->rstate, chan); /*~ Note the inversions here on both sides, which is cheap conversion to * boolean for the RHS! */ - if (!chan->local_disabled == !(hc->channel_flags & ROUTING_FLAGS_DISABLED)) + if (!local_disabled == !(hc->channel_flags & ROUTING_FLAGS_DISABLED)) return; update_local_channel(daemon, chan, direction, - chan->local_disabled, + local_disabled, hc->delay, hc->htlc_minimum, hc->base_fee, @@ -1555,7 +1557,11 @@ static bool handle_local_channel_update(struct peer *peer, const u8 *msg) /* Normal case: just toggle local_disabled, and generate broadcast in * maybe_update_local_channel when/if someone asks about it. */ - chan->local_disabled = disable; + if (disable) + local_disable_chan(peer->daemon->rstate, chan); + else + local_enable_chan(peer->daemon->rstate, chan); + return true; } @@ -1833,7 +1839,7 @@ static void gossip_send_keepalive_update(struct daemon *daemon, * local_disabled state */ update_local_channel(daemon, chan, hc->channel_flags & ROUTING_FLAGS_DIRECTION, - chan->local_disabled, + is_chan_local_disabled(daemon->rstate, chan), hc->delay, hc->htlc_minimum, hc->base_fee, @@ -1912,7 +1918,7 @@ static void gossip_disable_local_channels(struct daemon *daemon) return; for (c = first_chan(local_node, &i); c; c = next_chan(local_node, &i)) - c->local_disabled = true; + local_disable_chan(daemon->rstate, c); } /*~ Parse init message from lightningd: starts the daemon properly. */ @@ -2044,7 +2050,8 @@ static struct gossip_halfchannel_entry *hc_entry(const tal_t *ctx, } /*~ Marshal (possibly) both channel directions into entries. */ -static void append_channel(const struct gossip_getchannels_entry ***entries, +static void append_channel(struct routing_state *rstate, + const struct gossip_getchannels_entry ***entries, const struct chan *chan, const struct node_id *srcfilter) { @@ -2053,7 +2060,7 @@ static void append_channel(const struct gossip_getchannels_entry ***entries, e->node[0] = chan->nodes[0]->id; e->node[1] = chan->nodes[1]->id; e->sat = chan->sat; - e->local_disabled = chan->local_disabled; + e->local_disabled = is_chan_local_disabled(rstate, chan); e->public = is_chan_public(chan); e->short_channel_id = chan->scid; if (!srcfilter || node_id_eq(&e->node[0], srcfilter)) @@ -2092,7 +2099,7 @@ static struct io_plan *getchannels_req(struct io_conn *conn, if (scid) { chan = get_channel(daemon->rstate, scid); if (chan) - append_channel(&entries, chan, NULL); + append_channel(daemon->rstate, &entries, chan, NULL); } else if (source) { struct node *s = get_node(daemon->rstate, source); if (s) { @@ -2100,7 +2107,8 @@ static struct io_plan *getchannels_req(struct io_conn *conn, struct chan *c; for (c = first_chan(s, &i); c; c = next_chan(s, &i)) { - append_channel(&entries, c, source); + append_channel(daemon->rstate, + &entries, c, source); } } } else { @@ -2111,7 +2119,7 @@ static struct io_plan *getchannels_req(struct io_conn *conn, for (chan = uintmap_first(&daemon->rstate->chanmap, &idx); chan; chan = uintmap_after(&daemon->rstate->chanmap, &idx)) { - append_channel(&entries, chan, NULL); + append_channel(daemon->rstate, &entries, chan, NULL); } } @@ -2758,7 +2766,7 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn, chan = get_channel(rstate, &scid); if (chan) - chan->local_disabled = true; + local_disable_chan(rstate, chan); return daemon_conn_read_next(conn, daemon->master); } diff --git a/gossipd/routing.c b/gossipd/routing.c index 90c7b3d00..a81f03965 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -194,6 +194,7 @@ struct routing_state *new_routing_state(const tal_t *ctx, list_head_init(&rstate->pending_cannouncement); uintmap_init(&rstate->chanmap); uintmap_init(&rstate->unupdated_chanmap); + chan_map_init(&rstate->local_disabled_map); uintmap_init(&rstate->txout_failures); rstate->pending_node_map = tal(ctx, struct pending_node_map); @@ -374,6 +375,9 @@ static void destroy_chan(struct chan *chan, struct routing_state *rstate) broadcast_del(rstate->broadcasts, &chan->half[1].bcast); uintmap_del(&rstate->chanmap, chan->scid.u64); + + /* Remove from local_disabled_map if it's there. */ + chan_map_del(&rstate->local_disabled_map, chan); } static void init_half_chan(struct routing_state *rstate, @@ -423,10 +427,8 @@ struct chan *new_chan(struct routing_state *rstate, chan->scid = *scid; chan->nodes[n1idx] = n1; chan->nodes[!n1idx] = n2; - chan->txout_script = NULL; broadcastable_init(&chan->bcast); chan->sat = satoshis; - chan->local_disabled = false; add_chan(n2, chan); add_chan(n1, chan); @@ -579,10 +581,11 @@ static void bfg_one_edge(struct node *node, } /* Determine if the given half_chan is routable */ -static bool hc_is_routable(const struct chan *chan, int idx) +static bool hc_is_routable(struct routing_state *rstate, + const struct chan *chan, int idx) { - return !chan->local_disabled - && is_halfchan_enabled(&chan->half[idx]); + return is_halfchan_enabled(&chan->half[idx]) + && !is_chan_local_disabled(rstate, chan); } /* riskfactor is already scaled to per-block amount */ @@ -655,9 +658,9 @@ find_route(const tal_t *ctx, struct routing_state *rstate, struct short_channel_id, &c->scid)); - if (!hc_is_routable(chan, idx)) { + if (!hc_is_routable(rstate, chan, idx)) { SUPERVERBOSE("...unroutable (local_disabled = %i, is_halfchan_enabled = %i, unroutable_until = %i", - chan->local_disabled, + is_chan_local_disabled(rstate, chan), is_halfchan_enabled(&chan->half[idx]), chan->half[idx].unroutable_until >= now); continue; diff --git a/gossipd/routing.h b/gossipd/routing.h index da0987bc9..c6677abdf 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -42,7 +42,6 @@ struct half_chan { struct chan { struct short_channel_id scid; - u8 *txout_script; /* * half[0]->src == nodes[0] half[0]->dst == nodes[1] @@ -55,9 +54,6 @@ struct chan { /* Timestamp and index into store file */ struct broadcastable bcast; - /* Disabled locally (due to peer disconnect) */ - bool local_disabled; - struct amount_sat sat; }; @@ -201,6 +197,9 @@ struct routing_state { * checks if we get another announcement for the same scid. */ UINTMAP(bool) txout_failures; + /* A map of (local) disabled channels by short_channel_ids */ + struct chan_map local_disabled_map; + #if DEVELOPER /* Override local time for gossip messages */ struct timeabs *gossip_time; @@ -361,6 +360,28 @@ void memleak_remove_routing_tables(struct htable *memtable, */ struct timeabs gossip_time_now(const struct routing_state *rstate); +/* Because we can have millions of channels, and we only want a local_disable + * flag on ones connected to us, we keep a separate hashtable for that flag. + */ +static inline bool is_chan_local_disabled(struct routing_state *rstate, + const struct chan *chan) +{ + return chan_map_get(&rstate->local_disabled_map, &chan->scid) != NULL; +} + +static inline void local_disable_chan(struct routing_state *rstate, + const struct chan *chan) +{ + if (!is_chan_local_disabled(rstate, chan)) + chan_map_add(&rstate->local_disabled_map, chan); +} + +static inline void local_enable_chan(struct routing_state *rstate, + const struct chan *chan) +{ + chan_map_del(&rstate->local_disabled_map, chan); +} + /* Helper to convert on-wire addresses format to wireaddrs array */ struct wireaddr *read_addresses(const tal_t *ctx, const u8 *ser); #endif /* LIGHTNING_GOSSIPD_ROUTING_H */