diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 7e71e5b81..6ca0ff3e5 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -307,48 +307,136 @@ void maybe_send_own_node_announce(struct daemon *daemon, bool startup) update_own_node_announcement(daemon, startup); } -/* Our timer callbacks take a single argument, so we marshall everything - * we need into this structure: */ -struct local_cupdate { - struct daemon *daemon; - struct local_chan *local_chan; - - bool disable; - bool even_if_identical; - bool even_if_too_soon; - - u16 cltv_expiry_delta; - struct amount_msat htlc_minimum, htlc_maximum; - u32 fee_base_msat, fee_proportional_millionths; -}; - -/* This generates a `channel_update` message for one of our channels. We do - * this here, rather than in `channeld` because we (may) need to do it - * ourselves anyway if channeld dies, or when we refresh it once a week, - * and so we can avoid creating redundant ones. */ -static void update_local_channel(struct local_cupdate *lc /* frees! */) +/* Fast accessors for channel_update fields */ +static u8 *channel_flags_access(const u8 *channel_update) { - struct daemon *daemon = lc->daemon; - secp256k1_ecdsa_signature dummy_sig; - u8 *update, *msg; - u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec, next; - u8 message_flags, channel_flags; - struct chan *chan = lc->local_chan->chan; - struct half_chan *hc; - const int direction = lc->local_chan->direction; + /* BOLT #7: + * 1. type: 258 (`channel_update`) + * 2. data: + * * [`signature`:`signature`] + * * [`chain_hash`:`chain_hash`] + * * [`short_channel_id`:`short_channel_id`] + * * [`u32`:`timestamp`] + * * [`byte`:`message_flags`] + * * [`byte`:`channel_flags`] + */ + /* Note: 2 bytes for `type` field */ + return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8 + 4 + 1]); +} - /* Discard existing timer. */ - lc->local_chan->channel_update_timer - = tal_free(lc->local_chan->channel_update_timer); +static u8 *timestamp_access(const u8 *channel_update) +{ + /* BOLT #7: + * 1. type: 258 (`channel_update`) + * 2. data: + * * [`signature`:`signature`] + * * [`chain_hash`:`chain_hash`] + * * [`short_channel_id`:`short_channel_id`] + * * [`u32`:`timestamp`] + * * [`byte`:`message_flags`] + * * [`byte`:`channel_flags`] + */ + /* Note: 2 bytes for `type` field */ + return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8]); +} - /* So valgrind doesn't complain */ - memset(&dummy_sig, 0, sizeof(dummy_sig)); +static bool is_disabled(const u8 *channel_update) +{ + return *channel_flags_access(channel_update) & ROUTING_FLAGS_DISABLED; +} + +static bool is_enabled(const u8 *channel_update) +{ + return !is_disabled(channel_update); +} + + +static u32 timestamp_for_update(struct daemon *daemon, + const u32 *prev_timestamp, + bool disable) +{ + u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; /* Create an unsigned channel_update: we backdate enables, so * we can always send a disable in an emergency. */ - if (!lc->disable) + if (!disable) timestamp -= GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); + if (prev_timestamp) { + /* Timestamps can't go backwards! */ + if (timestamp < *prev_timestamp) + timestamp = *prev_timestamp + 1; + + /* If we ever use set-based propagation, ensuring the toggle + * the lower bit in consecutive timestamps makes it more + * robust. */ + if ((timestamp & 1) == (*prev_timestamp & 1)) + timestamp++; + } + + return timestamp; +} + +static u8 *sign_and_timestamp_update(const tal_t *ctx, + struct daemon *daemon, + const struct chan *chan, + int direction, + u8 *unsigned_update TAKES) +{ + u8 *msg, *update; + be32 timestamp; + const u32 *prev_timestamp; + const struct half_chan *hc = &chan->half[direction]; + + if (is_halfchan_defined(hc)) + prev_timestamp = &hc->bcast.timestamp; + else + prev_timestamp = NULL; + + /* Get an appropriate timestamp */ + timestamp = cpu_to_be32(timestamp_for_update(daemon, + prev_timestamp, + is_disabled(unsigned_update))); + memcpy(timestamp_access(unsigned_update), ×tamp, sizeof(timestamp)); + + /* Note that we treat the hsmd as synchronous. This is simple (no + * callback hell)!, but may need to change to async if we ever want + * remote HSMs */ + if (!wire_sync_write(HSM_FD, + towire_hsmd_cupdate_sig_req(tmpctx, unsigned_update))) { + status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s", + strerror(errno)); + } + + msg = wire_sync_read(tmpctx, HSM_FD); + if (!msg || !fromwire_hsmd_cupdate_sig_reply(ctx, msg, &update)) { + status_failed(STATUS_FAIL_HSM_IO, + "Reading cupdate_sig_req: %s", + strerror(errno)); + } + + if (taken(unsigned_update)) + tal_free(unsigned_update); + + return update; +} + +static u8 *create_unsigned_update(const tal_t *ctx, + const struct short_channel_id *scid, + int direction, + bool disable, + u16 cltv_expiry_delta, + struct amount_msat htlc_minimum, + struct amount_msat htlc_maximum, + u32 fee_base_msat, + u32 fee_proportional_millionths) +{ + secp256k1_ecdsa_signature dummy_sig; + u8 message_flags, channel_flags; + + /* So valgrind doesn't complain */ + memset(&dummy_sig, 0, sizeof(dummy_sig)); + /* BOLT #7: * * The `channel_flags` bitfield is used to indicate the direction of @@ -362,7 +450,7 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) * | 1 | `disable` | Disable the channel. | */ channel_flags = direction; - if (lc->disable) + if (disable) channel_flags |= ROUTING_FLAGS_DISABLED; /* BOLT #7: @@ -376,101 +464,43 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) */ message_flags = 0 | ROUTING_OPT_HTLC_MAX_MSAT; - /* Convenience variable. */ - hc = &chan->half[direction]; - - /* If we ever use set-based propagation, ensuring the toggle - * the lower bit in consecutive timestamps makes it more - * robust. */ - if (is_halfchan_defined(hc) - && (timestamp & 1) == (hc->bcast.timestamp & 1)) - timestamp++; - - /* We create an update with a dummy signature, and hand to hsmd to get - * it signed. */ - update = towire_channel_update_option_channel_htlc_max(tmpctx, &dummy_sig, + /* We create an update with a dummy signature and timestamp. */ + return towire_channel_update_option_channel_htlc_max(ctx, + &dummy_sig, /* sig set later */ &chainparams->genesis_blockhash, - &chan->scid, - timestamp, + scid, + 0, /* timestamp set later */ message_flags, channel_flags, - lc->cltv_expiry_delta, - lc->htlc_minimum, - lc->fee_base_msat, - lc->fee_proportional_millionths, - lc->htlc_maximum); + cltv_expiry_delta, + htlc_minimum, + fee_base_msat, + fee_proportional_millionths, + htlc_maximum); +} - if (is_halfchan_defined(hc)) { - /* Suppress duplicates. */ - if (!lc->even_if_identical - && !cupdate_different(daemon->rstate->gs, hc, update)) { - tal_free(lc); - return; - } +static void apply_update(struct daemon *daemon, + const struct chan *chan, + int direction, + u8 *update TAKES) +{ + u8 *msg; + struct peer *peer = find_peer(daemon, &chan->nodes[!direction]->id); - /* Is it too soon to send another update? */ - next = hc->bcast.timestamp - + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); - - if (timestamp < next && !lc->even_if_too_soon) { - status_debug("channel_update %s/%u: delaying %u secs", - type_to_string(tmpctx, - struct short_channel_id, - &chan->scid), - direction, - next - timestamp); - lc->local_chan->channel_update_timer - = new_reltimer(&daemon->timers, lc, - time_from_sec(next - timestamp), - update_local_channel, - lc); - /* If local chan vanishes, so does update, and timer. */ - notleak(tal_steal(lc->local_chan, lc)); - return; - } - } - - /* Note that we treat the hsmd as synchronous. This is simple (no - * callback hell)!, but may need to change to async if we ever want - * remote HSMs */ - if (!wire_sync_write(HSM_FD, - towire_hsmd_cupdate_sig_req(tmpctx, update))) { - status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s", - strerror(errno)); - } - - msg = wire_sync_read(tmpctx, HSM_FD); - if (!msg || !fromwire_hsmd_cupdate_sig_reply(tmpctx, msg, &update)) { - status_failed(STATUS_FAIL_HSM_IO, - "Reading cupdate_sig_req: %s", - strerror(errno)); - } - - /* BOLT #7: - * - * The origin node: - *... - * - MAY create a `channel_update` to communicate the channel parameters to the - * channel peer, even though the channel has not yet been announced (i.e. the - * `announce_channel` bit was not set). - */ if (!is_chan_public(chan)) { + /* Save and restore taken state, for handle_channel_update */ + bool update_taken = taken(update); + /* handle_channel_update will not put private updates in the * broadcast list, but we send it direct to the peer (if we * have one connected) now */ - struct peer *peer = find_peer(daemon, - &chan->nodes[!direction]->id); if (peer) queue_peer_msg(peer, update); + + if (update_taken) + take(update); } - /* We feed it into routing.c like any other channel_update; it may - * discard it (eg. non-public channel), but it should not complain - * about it being invalid! __func__ is a magic C constant which - * expands to this function name. */ - msg = handle_channel_update(daemon->rstate, update, - find_peer(daemon, - &chan->nodes[!direction]->id), - NULL, true); + msg = handle_channel_update(daemon->rstate, update, peer, NULL, true); if (msg) status_failed(STATUS_FAIL_INTERNAL_ERROR, "%s: rejected local channel update %s: %s", @@ -481,72 +511,181 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) * tmpctx, so it's actually OK. */ tal_hex(tmpctx, update), tal_hex(tmpctx, msg)); - - tal_free(lc); } -/* This is a refresh of a local channel: sends an update if one is needed. */ -void refresh_local_channel(struct daemon *daemon, - struct local_chan *local_chan, - bool even_if_identical) +static void sign_timestamp_and_apply_update(struct daemon *daemon, + const struct chan *chan, + int direction, + u8 *update TAKES) { - const struct half_chan *hc; - struct local_cupdate *lc; - u8 *prev; - secp256k1_ecdsa_signature signature; - struct bitcoin_blkid chain_hash; - struct short_channel_id short_channel_id; - u32 timestamp; - u8 message_flags, channel_flags; + update = sign_and_timestamp_update(NULL, daemon, chan, direction, + update); + apply_update(daemon, chan, direction, take(update)); +} - hc = &local_chan->chan->half[local_chan->direction]; +/* We don't want to thrash the gossip network, so we often defer sending an + * update. We track them here. */ +struct deferred_update { + struct daemon *daemon; + /* Off daemon->deferred_updates */ + struct list_node list; + /* Channel it's for (and owner) */ + const struct chan *chan; + int direction; + /* Timer which will fire when it's time to apply. */ + struct oneshot *channel_update_timer; + /* The actual `update_channel` to apply */ + u8 *update; +}; - /* Don't generate a channel_update for an uninitialized channel. */ - if (!is_halfchan_defined(hc)) - return; +static struct deferred_update *find_deferred_update(struct daemon *daemon, + const struct chan *chan) +{ + struct deferred_update *du; - /* If there's an update pending already, force it to apply now. */ - if (local_chan->channel_update_timer) { - lc = reltimer_arg(local_chan->channel_update_timer); - lc->even_if_too_soon = true; - update_local_channel(lc); - /* Free timer */ - local_chan->channel_update_timer - = tal_free(local_chan->channel_update_timer); + list_for_each(&daemon->deferred_updates, du, list) { + if (du->chan == chan) + return du; } + return NULL; +} - lc = tal(NULL, struct local_cupdate); - lc->daemon = daemon; - lc->local_chan = local_chan; - lc->even_if_identical = even_if_identical; - lc->even_if_too_soon = false; +static void destroy_deferred_update(struct deferred_update *du) +{ + list_del(&du->list); +} + +static void apply_deferred_update(struct deferred_update *du) +{ + apply_update(du->daemon, du->chan, du->direction, take(du->update)); + tal_free(du); +} + +static void defer_update(struct daemon *daemon, + u32 delay, + const struct chan *chan, + int direction, + u8 *unsigned_update TAKES) +{ + struct deferred_update *du; + + /* Override any existing one */ + tal_free(find_deferred_update(daemon, chan)); + + /* If chan is gone, so are we. */ + du = tal(chan, struct deferred_update); + du->daemon = daemon; + du->chan = chan; + du->direction = direction; + du->update = sign_and_timestamp_update(du, daemon, chan, direction, + unsigned_update); + if (delay != 0xFFFFFFFF) + du->channel_update_timer = new_reltimer(&daemon->timers, du, + time_from_sec(delay), + apply_deferred_update, + du); + else + du->channel_update_timer = NULL; + list_add_tail(&daemon->deferred_updates, &du->list); + tal_add_destructor(du, destroy_deferred_update); +} + +/* If there is a pending update for this local channel, apply immediately. */ +bool local_channel_update_latest(struct daemon *daemon, struct chan *chan) +{ + struct deferred_update *du; + + du = find_deferred_update(daemon, chan); + if (!du) + return false; + + /* Frees itself */ + apply_deferred_update(du); + return true; +} + +/* Get previous update. */ +static u8 *prev_update(const tal_t *ctx, + struct daemon *daemon, const struct chan *chan, int direction) +{ + u8 *prev; + + if (!is_halfchan_defined(&chan->half[direction])) + return NULL; prev = cast_const(u8 *, gossip_store_get(tmpctx, daemon->rstate->gs, - local_chan->chan->half[local_chan->direction] - .bcast.index)); + chan->half[direction].bcast.index)); /* If it's a private update, unwrap */ - fromwire_gossip_store_private_update(tmpctx, prev, &prev); + if (!fromwire_gossip_store_private_update(ctx, prev, &prev)) + tal_steal(ctx, prev); + return prev; +} + +/* This is a refresh of a local channel (after 13 days). */ +void refresh_local_channel(struct daemon *daemon, + struct chan *chan, int direction) +{ + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum, htlc_maximum; + u32 fee_base_msat, fee_proportional_millionths, timestamp; + u8 *prev, *update; + u8 message_flags, channel_flags; + secp256k1_ecdsa_signature signature; + struct bitcoin_blkid chain_hash; + struct short_channel_id short_channel_id; + + /* If there's a pending update, apply it and we're done. */ + if (local_channel_update_latest(daemon, chan)) + return; + + prev = prev_update(tmpctx, daemon, chan, direction); + if (!prev) + return; if (!fromwire_channel_update_option_channel_htlc_max(prev, &signature, &chain_hash, &short_channel_id, ×tamp, &message_flags, &channel_flags, - &lc->cltv_expiry_delta, - &lc->htlc_minimum, - &lc->fee_base_msat, - &lc->fee_proportional_millionths, - &lc->htlc_maximum)) { + &cltv_expiry_delta, + &htlc_minimum, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum)) { status_broken("Could not decode local channel_update %s!", tal_hex(tmpctx, prev)); - tal_free(lc); return; } - lc->disable = (channel_flags & ROUTING_FLAGS_DISABLED) - || local_chan->local_disabled; - update_local_channel(lc); + /* BOLT #7: + * + * The `channel_flags` bitfield is used to indicate the direction of + * the channel: it identifies the node that this update originated + * from and signals various options concerning the channel. The + * following table specifies the meaning of its individual bits: + * + * | Bit Position | Name | Meaning | + * | ------------- | ----------- | -------------------------------- | + * | 0 | `direction` | Direction this update refers to. | + * | 1 | `disable` | Disable the channel. | + */ + if (direction != (channel_flags & ROUTING_FLAGS_DIRECTION)) { + status_broken("Wrong channel direction %s!", + tal_hex(tmpctx, prev)); + return; + } + + /* Don't refresh disabled channels. */ + if (channel_flags & ROUTING_FLAGS_DISABLED) + return; + + update = create_unsigned_update(NULL, &short_channel_id, direction, + false, cltv_expiry_delta, + htlc_minimum, htlc_maximum, + fee_base_msat, + fee_proportional_millionths); + sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); } /* channeld asks us to update the local channel. */ @@ -555,43 +694,141 @@ bool handle_local_channel_update(struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; - struct local_cupdate *lc = tal(tmpctx, struct local_cupdate); - - lc->daemon = daemon; - lc->even_if_identical = false; - lc->even_if_too_soon = false; + bool disable; + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum, htlc_maximum; + u32 fee_base_msat, fee_proportional_millionths; + struct chan *chan; + int direction; + u8 *unsigned_update; + const struct half_chan *hc; /* FIXME: We should get scid from lightningd when setting up the * connection, so no per-peer daemon can mess with channels other than * its own! */ if (!fromwire_gossipd_local_channel_update(msg, &scid, - &lc->disable, - &lc->cltv_expiry_delta, - &lc->htlc_minimum, - &lc->fee_base_msat, - &lc->fee_proportional_millionths, - &lc->htlc_maximum)) { + &disable, + &cltv_expiry_delta, + &htlc_minimum, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum)) { status_peer_broken(src, "bad local_channel_update %s", tal_hex(tmpctx, msg)); return false; } - lc->local_chan = local_chan_map_get(&daemon->rstate->local_chan_map, - &scid); + chan = get_channel(daemon->rstate, &scid); /* Can theoretically happen if channel just closed. */ - if (!lc->local_chan) { + if (!chan) { status_peer_debug(src, "local_channel_update for unknown %s", type_to_string(tmpctx, struct short_channel_id, &scid)); return true; } - /* Remove soft local_disabled flag, if they're marking it enabled. */ - if (!lc->disable) - local_enable_chan(daemon->rstate, lc->local_chan->chan); + if (!local_direction(daemon->rstate, chan, &direction)) { + status_peer_broken(src, "bad local_channel_update chan %s", + type_to_string(tmpctx, + struct short_channel_id, + &scid)); + return false; + } - /* Apply the update they told us */ - update_local_channel(tal_steal(NULL, lc)); + unsigned_update = create_unsigned_update(tmpctx, &scid, direction, + disable, cltv_expiry_delta, + htlc_minimum, htlc_maximum, + fee_base_msat, + fee_proportional_millionths); + + hc = &chan->half[direction]; + + /* Ignore duplicates. */ + if (is_halfchan_defined(hc) + && !cupdate_different(daemon->rstate->gs, hc, unsigned_update)) + return true; + + /* Too early? Defer (don't worry if it's unannounced). */ + if (hc && is_chan_public(chan)) { + u32 now = time_now().ts.tv_sec; + u32 next_time = hc->bcast.timestamp + + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); + if (now < next_time) { + defer_update(daemon, next_time - now, + chan, direction, take(unsigned_update)); + return true; + } + } + + sign_timestamp_and_apply_update(daemon, chan, direction, + take(unsigned_update)); return true; } + +/* Take update, set/unset disabled flag (and update timestamp). + */ +static void set_disable_flag(u8 *channel_update, bool disable) +{ + u8 *channel_flags = channel_flags_access(channel_update); + + if (disable) + *channel_flags |= ROUTING_FLAGS_DISABLED; + else + *channel_flags &= ~ROUTING_FLAGS_DISABLED; +} + +/* We don't immediately disable, to avoid flapping. */ +void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction) +{ + struct deferred_update *du; + u8 *update = prev_update(tmpctx, daemon, chan, direction); + if (!update) + return; + + du = find_deferred_update(daemon, chan); + + /* Will a deferred update disable it already? OK, nothing to do. */ + if (du && is_disabled(du->update)) + return; + + /* OK, we definitely don't want deferred update to re-enable! */ + tal_free(du); + + /* Is it already disabled? */ + if (is_disabled(update)) + return; + + /* This is deferred indefinitely (flushed if needed though) */ + set_disable_flag(update, true); + defer_update(daemon, 0xFFFFFFFF, chan, direction, take(update)); +} + +void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction) +{ + struct deferred_update *du; + u8 *update = prev_update(tmpctx, daemon, chan, direction); + + + if (!update) + return; + + du = find_deferred_update(daemon, chan); + + /* Will a deferred update enable it? If so, apply immediately. */ + if (du && is_enabled(du->update)) { + apply_deferred_update(du); + return; + } + + /* OK, we definitely don't want deferred update to disable! */ + tal_free(du); + + /* Is it already enabled? */ + if (is_enabled(update)) + return; + + /* Apply this enabling update immediately. */ + set_disable_flag(update, false); + sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); +} diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index d58f5151e..2e7b396f5 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -35,10 +35,18 @@ bool nannounce_different(struct gossip_store *gs, /* Should we announce our own node? Called at strategic places. */ void maybe_send_own_node_announce(struct daemon *daemon, bool startup); -/* This is a refresh of a local channel: sends an update if one is needed. */ +/* Flush any pending changes to this channel. */ +bool local_channel_update_latest(struct daemon *daemon, struct chan *chan); + +/* Disable this local channel (lazily) */ +void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction); + +/* Re-enable this local channel */ +void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction); + +/* This is a refresh of a local channel which is > 13 days old. */ void refresh_local_channel(struct daemon *daemon, - struct local_chan *local_chan, - bool even_if_identical); + struct chan *chan, int direction); /* channeld asks us to update the local channel. */ bool handle_local_channel_update(struct daemon *daemon, diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 3fc121b83..098fe652f 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -44,15 +44,32 @@ * whole-channel flag which indicates it's not available; we use this when a * peer disconnects, and generate a `channel_update` to tell the world lazily * when someone asks. */ -static void peer_disable_channels(struct daemon *daemon, struct node *node) +static void peer_disable_channels(struct daemon *daemon, const struct node *node) { /* If this peer had a channel with us, mark it disabled. */ struct chan_map_iter i; - struct chan *c; + const struct chan *c; for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - if (node_id_eq(&other_node(node, c)->id, &daemon->id)) - local_disable_chan(daemon->rstate, c); + int direction; + if (!local_direction(daemon->rstate, c, &direction)) + continue; + local_disable_chan(daemon, c, direction); + } +} + +/*~ This cancels the soft-disables when the peer reconnects. */ +static void peer_enable_channels(struct daemon *daemon, const struct node *node) +{ + /* If this peer had a channel with us, mark it disabled. */ + struct chan_map_iter i; + const struct chan *c; + + for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { + int direction; + if (!local_direction(daemon->rstate, c, &direction)) + continue; + local_enable_chan(daemon, c, direction); } } @@ -267,10 +284,10 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg) static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) { struct short_channel_id scid; - struct local_chan *local_chan; struct chan *chan; const u8 *update; struct routing_state *rstate = peer->daemon->rstate; + int direction; if (!fromwire_gossipd_get_update(msg, &scid)) { status_broken("peer %s sent bad gossip_get_update %s", @@ -280,8 +297,8 @@ static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) } /* It's possible that the channel has just closed (though v. unlikely) */ - local_chan = local_chan_map_get(&rstate->local_chan_map, &scid); - if (!local_chan) { + chan = get_channel(rstate, &scid); + if (!chan) { status_unusual("peer %s scid %s: unknown channel", type_to_string(tmpctx, struct node_id, &peer->id), type_to_string(tmpctx, struct short_channel_id, @@ -290,18 +307,24 @@ static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) goto out; } - chan = local_chan->chan; - /* Since we're going to send it out, make sure it's up-to-date. */ - refresh_local_channel(peer->daemon, local_chan, false); + local_channel_update_latest(peer->daemon, chan); + + if (!local_direction(rstate, chan, &direction)) { + status_peer_broken(&peer->id, "Chan %s is not local?", + type_to_string(tmpctx, struct short_channel_id, + &scid)); + update = NULL; + goto out; + } /* It's possible this is zero, if we've never sent a channel_update * for that channel. */ - if (!is_halfchan_defined(&chan->half[local_chan->direction])) + if (!is_halfchan_defined(&chan->half[direction])) update = NULL; else update = gossip_store_get(tmpctx, rstate->gs, - chan->half[local_chan->direction].bcast.index); + chan->half[direction].bcast.index); out: status_peer_debug(&peer->id, "schanid %s: %s update", type_to_string(tmpctx, struct short_channel_id, &scid), @@ -808,6 +831,7 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, const u8 *msg) { struct peer *peer = tal(conn, struct peer); + struct node *node; int fds[2]; int gossip_store_fd; struct gossip_state *gs; @@ -869,6 +893,10 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, /* Free peer if conn closed (destroy_peer closes conn if peer freed) */ tal_steal(peer->dc, peer); + node = get_node(daemon->rstate, &peer->id); + if (node) + peer_enable_channels(daemon, node); + /* This sends the initial timestamp filter. */ seeker_setup_peer_gossip(daemon->seeker, peer); @@ -967,23 +995,6 @@ static struct io_plan *connectd_req(struct io_conn *conn, return io_close(conn); } -/*~ This is our 13-day timer callback for refreshing our channels. This - * was added to the spec because people abandoned their channels without - * closing them. */ -static void gossip_send_keepalive_update(struct daemon *daemon, - struct local_chan *local_chan) -{ - status_debug("Sending keepalive channel_update for %s/%u", - type_to_string(tmpctx, struct short_channel_id, - &local_chan->chan->scid), - local_chan->direction); - - /* As a side-effect, this will create an update which matches the - * local_disabled state */ - refresh_local_channel(daemon, local_chan, true); -} - - /* BOLT #7: * * A node: @@ -1016,11 +1027,13 @@ static void gossip_refresh_network(struct daemon *daemon) struct chan *c; for (c = first_chan(n, &i); c; c = next_chan(n, &i)) { - struct local_chan *local_chan; struct half_chan *hc; + int direction; - local_chan = is_local_chan(daemon->rstate, c); - hc = &c->half[local_chan->direction]; + if (!local_direction(daemon->rstate, c, &direction)) + continue; + + hc = &c->half[direction]; if (!is_halfchan_defined(hc)) { /* Connection is not announced yet, so don't even @@ -1033,12 +1046,12 @@ static void gossip_refresh_network(struct daemon *daemon) continue; } - if (is_chan_local_disabled(daemon->rstate, c)) { - /* Only send keepalives for active connections */ - continue; - } - - gossip_send_keepalive_update(daemon, local_chan); + status_debug("Sending keepalive channel_update" + " for %s/%u", + type_to_string(tmpctx, + struct short_channel_id, + &c->scid), direction); + refresh_local_channel(daemon, c, direction); } } @@ -1060,7 +1073,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)) - local_disable_chan(daemon->rstate, c); + local_disable_chan(daemon, c, half_chan_idx(local_node, c)); } struct peer *random_peer(struct daemon *daemon, @@ -1244,24 +1257,34 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn, struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; - struct local_chan *local_chan; + struct chan *chan; const u8 *stripped_update; if (!fromwire_gossipd_get_stripped_cupdate(msg, &scid)) master_badmsg(WIRE_GOSSIPD_GET_STRIPPED_CUPDATE, msg); - local_chan = local_chan_map_get(&daemon->rstate->local_chan_map, &scid); - if (!local_chan) { + chan = get_channel(daemon->rstate, &scid); + if (!chan) { status_debug("Failed to resolve local channel %s", type_to_string(tmpctx, struct short_channel_id, &scid)); stripped_update = NULL; } else { + int direction; const struct half_chan *hc; - /* Since we're going to use it, make sure it's up-to-date. */ - refresh_local_channel(daemon, local_chan, false); + if (!local_direction(daemon->rstate, chan, &direction)) { + status_broken("%s is a non-local channel!", + type_to_string(tmpctx, + struct short_channel_id, + &scid)); + stripped_update = NULL; + goto out; + } - hc = &local_chan->chan->half[local_chan->direction]; + /* Since we're going to use it, make sure it's up-to-date. */ + local_channel_update_latest(daemon, chan); + + hc = &chan->half[direction]; if (is_halfchan_defined(hc)) { const u8 *update; @@ -1272,6 +1295,8 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn, } else stripped_update = NULL; } + +out: daemon_conn_send(daemon->master, take(towire_gossipd_get_stripped_cupdate_reply(NULL, stripped_update))); @@ -1423,8 +1448,18 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn, master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE, msg); chan = get_channel(rstate, &scid); - if (chan) - local_disable_chan(rstate, chan); + if (chan) { + int direction; + + if (!local_direction(rstate, chan, &direction)) { + status_broken("Non-local channel close %s", + type_to_string(tmpctx, + struct short_channel_id, + &scid)); + } else { + local_disable_chan(daemon, chan, direction); + } + } return daemon_conn_read_next(conn, daemon->master); } @@ -1522,6 +1557,7 @@ int main(int argc, char *argv[]) daemon->node_announce_timer = NULL; daemon->current_blockheight = 0; /* i.e. unknown */ daemon->rates = NULL; + list_head_init(&daemon->deferred_updates); /* Tell the ecdh() function how to talk to hsmd */ ecdh_hsmd_setup(HSM_FD, status_failed); diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index fe2082c74..af1d435ae 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -60,6 +60,9 @@ struct daemon { /* The channel lease rates we're advertising */ const struct lease_rates *rates; + + /* Any of our channel_updates we're deferring. */ + struct list_head deferred_updates; }; struct range_query_reply { diff --git a/gossipd/routing.c b/gossipd/routing.c index 560e14239..58b1d5c78 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -198,7 +198,6 @@ static void destroy_routing_state(struct routing_state *rstate) /* Free up our htables */ pending_cannouncement_map_clear(&rstate->pending_cannouncements); - local_chan_map_clear(&rstate->local_chan_map); } /* We don't check this when loading from the gossip_store: that would break @@ -226,7 +225,6 @@ static void memleak_help_routing_tables(struct htable *memtable, memleak_remove_htable(memtable, &rstate->nodes->raw); memleak_remove_htable(memtable, &rstate->pending_node_map->raw); memleak_remove_htable(memtable, &rstate->pending_cannouncements.raw); - memleak_remove_htable(memtable, &rstate->local_chan_map.raw); memleak_remove_uintmap(memtable, &rstate->unupdated_chanmap); for (n = node_map_first(rstate->nodes, &nit); @@ -295,7 +293,6 @@ struct routing_state *new_routing_state(const tal_t *ctx, uintmap_init(&rstate->chanmap); uintmap_init(&rstate->unupdated_chanmap); - local_chan_map_init(&rstate->local_chan_map); rstate->num_txout_failures = 0; uintmap_init(&rstate->txout_failures); uintmap_init(&rstate->txout_failures_old); @@ -524,36 +521,6 @@ static void bad_gossip_order(const u8 *msg, details); } -static void destroy_local_chan(struct local_chan *local_chan, - struct routing_state *rstate) -{ - if (!local_chan_map_del(&rstate->local_chan_map, local_chan)) - abort(); -} - -static void maybe_add_local_chan(struct routing_state *rstate, - struct chan *chan) -{ - int direction; - struct local_chan *local_chan; - - if (node_id_eq(&chan->nodes[0]->id, &rstate->local_id)) - direction = 0; - else if (node_id_eq(&chan->nodes[1]->id, &rstate->local_id)) - direction = 1; - else - return; - - local_chan = tal(chan, struct local_chan); - local_chan->chan = chan; - local_chan->direction = direction; - local_chan->local_disabled = false; - local_chan->channel_update_timer = NULL; - - local_chan_map_add(&rstate->local_chan_map, local_chan); - tal_add_destructor2(local_chan, destroy_local_chan, rstate); -} - struct chan *new_chan(struct routing_state *rstate, const struct short_channel_id *scid, const struct node_id *id1, @@ -595,8 +562,6 @@ struct chan *new_chan(struct routing_state *rstate, uintmap_add(&rstate->chanmap, scid->u64, chan); - /* Initialize shadow structure if it's local */ - maybe_add_local_chan(rstate, chan); return chan; } diff --git a/gossipd/routing.h b/gossipd/routing.h index 1a8a08d0c..e33d63061 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -94,22 +94,6 @@ static inline bool chan_eq_scid(const struct chan *c, HTABLE_DEFINE_TYPE(struct chan, chan_map_scid, hash_scid, chan_eq_scid, chan_map); -/* Container for local channel pointers. */ -static inline const struct short_channel_id *local_chan_map_scid(const struct local_chan *local_chan) -{ - return &local_chan->chan->scid; -} - -static inline bool local_chan_eq_scid(const struct local_chan *local_chan, - const struct short_channel_id *scid) -{ - return short_channel_id_eq(scid, &local_chan->chan->scid); -} - -HTABLE_DEFINE_TYPE(struct local_chan, - local_chan_map_scid, hash_scid, local_chan_eq_scid, - local_chan_map); - /* For a small number of channels (by far the most common) we use a simple * array, with empty buckets NULL. For larger, we use a proper hash table, * with the extra allocation that implies. */ @@ -191,33 +175,13 @@ HTABLE_DEFINE_TYPE(struct pending_cannouncement, panding_cannouncement_map_scid, struct pending_node_map; struct unupdated_channel; -/* Fast versions: if you know n is one end of the channel */ -static inline struct node *other_node(const struct node *n, - const struct chan *chan) +/* If you know n is one end of the channel, get index of src == n */ +static inline int half_chan_idx(const struct node *n, const struct chan *chan) { int idx = (chan->nodes[1] == n); assert(chan->nodes[0] == n || chan->nodes[1] == n); - return chan->nodes[!idx]; -} - -/* If you know n is one end of the channel, get connection src == n */ -static inline struct half_chan *half_chan_from(const struct node *n, - struct chan *chan) -{ - int idx = (chan->nodes[1] == n); - - assert(chan->nodes[0] == n || chan->nodes[1] == n); - return &chan->half[idx]; -} - -/* If you know n is one end of the channel, get index dst == n */ -static inline int half_chan_to(const struct node *n, const struct chan *chan) -{ - int idx = (chan->nodes[1] == n); - - assert(chan->nodes[0] == n || chan->nodes[1] == n); - return !idx; + return idx; } struct routing_state { @@ -255,9 +219,6 @@ struct routing_state { UINTMAP(bool) txout_failures, txout_failures_old; struct oneshot *txout_failure_timer; - /* A map of local channels by short_channel_ids */ - struct local_chan_map local_chan_map; - /* Highest timestamp of gossip we accepted (before now) */ u32 last_timestamp; @@ -427,41 +388,11 @@ bool routing_add_private_channel(struct routing_state *rstate, */ struct timeabs gossip_time_now(const struct routing_state *rstate); -static inline struct local_chan *is_local_chan(struct routing_state *rstate, - const struct chan *chan) -{ - return local_chan_map_get(&rstate->local_chan_map, &chan->scid); -} - /* Would we ratelimit a channel_update with this timestamp? */ bool would_ratelimit_cupdate(struct routing_state *rstate, const struct half_chan *hc, u32 timestamp); -/* 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) -{ - struct local_chan *local_chan = is_local_chan(rstate, chan); - return local_chan && local_chan->local_disabled; -} - -static inline void local_disable_chan(struct routing_state *rstate, - const struct chan *chan) -{ - struct local_chan *local_chan = is_local_chan(rstate, chan); - local_chan->local_disabled = true; -} - -static inline void local_enable_chan(struct routing_state *rstate, - const struct chan *chan) -{ - struct local_chan *local_chan = is_local_chan(rstate, chan); - local_chan->local_disabled = false; -} - /* Remove channel from store: announcement and any updates. */ void remove_channel_from_store(struct routing_state *rstate, struct chan *chan); diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 473554f3f..b7bfd6a68 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -203,6 +203,15 @@ void json_object_end(struct json_stream *js UNNEEDED) /* Generated stub for json_object_start */ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) { fprintf(stderr, "json_object_start called!\n"); abort(); } +/* Generated stub for local_channel_update_latest */ +bool local_channel_update_latest(struct daemon *daemon UNNEEDED, struct chan *chan UNNEEDED) +{ fprintf(stderr, "local_channel_update_latest called!\n"); abort(); } +/* Generated stub for local_disable_chan */ +void local_disable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) +{ fprintf(stderr, "local_disable_chan called!\n"); abort(); } +/* Generated stub for local_enable_chan */ +void local_enable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) +{ fprintf(stderr, "local_enable_chan called!\n"); abort(); } /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } @@ -258,8 +267,7 @@ void query_unknown_node(struct seeker *seeker UNNEEDED, struct peer *peer UNNEED { fprintf(stderr, "query_unknown_node called!\n"); abort(); } /* Generated stub for refresh_local_channel */ void refresh_local_channel(struct daemon *daemon UNNEEDED, - struct local_chan *local_chan UNNEEDED, - bool even_if_identical UNNEEDED) + struct chan *chan UNNEEDED, int direction UNNEEDED) { fprintf(stderr, "refresh_local_channel called!\n"); abort(); } /* Generated stub for remove_channel_from_store */ void remove_channel_from_store(struct routing_state *rstate UNNEEDED,