Browse Source

gossipd: don't create struct chan for yet-to-be-updated channels.

We currently create a struct chan when we receive a `channel_announcement`,
but we can only broadcast once we have a `channel_update` (since that
provides the timestamp).

This means a `struct chan` can be in a weird state where it exists,
but is unusable (can't use without an update), and also means we need to
keep the channel_announcement message around until an update arrives, so
we can put it in the gossip_store.

Instead, keep track of these "unupdated" channels separately, and check
for them in all the places we search for a specific channel to update.

MCP results from 5 runs, min-max(mean +/- stddev):
	store_load_msec:30640-33236(32202+/-8.7e+02)
	vsz_kb:1812956
	store_rewrite_sec:13.410000-16.970000(14.438+/-1.3)
	listnodes_sec:0.590000-0.660000(0.62+/-0.033)
	listchannels_sec:28.140000-29.560000(28.816+/-0.56)
	routing_sec:29.530000-32.590000(30.352+/-1.1)
	peer_write_all_sec:60.380000-61.320000(60.836+/-0.37)

MCP notable changes from previous patch (>1 stddev):
	-vsz_kb:1812904
	+vsz_kb:1812956
	-store_rewrite_sec:21.390000-27.070000(23.596+/-2.4)
	+store_rewrite_sec:13.410000-16.970000(14.438+/-1.3)
	-listnodes_sec:1.120000-1.230000(1.176+/-0.044)
	+listnodes_sec:0.590000-0.660000(0.62+/-0.033)
	-listchannels_sec:38.900000-50.580000(44.716+/-3.9)
	+listchannels_sec:28.140000-29.560000(28.816+/-0.56)
	-routing_sec:45.080000-48.160000(46.814+/-1.1)
	+routing_sec:29.530000-32.590000(30.352+/-1.1)
	-peer_write_all_sec:58.780000-87.150000(72.278+/-9.7)
	+peer_write_all_sec:60.380000-61.320000(60.836+/-0.37)

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
pr-2587
Rusty Russell 6 years ago
committed by neil saitug
parent
commit
e02f5817fe
  1. 223
      gossipd/routing.c
  2. 5
      gossipd/routing.h

223
gossipd/routing.c

@ -73,6 +73,36 @@ HTABLE_DEFINE_TYPE(struct pending_node_announce, pending_node_announce_keyof,
node_map_hash_key, pending_node_announce_eq,
pending_node_map);
/* We keep around announcements for channels until we have an
* update for them (which gives us their timestamp) */
struct unupdated_channel {
/* The channel_announcement message */
const u8 *channel_announce;
/* The short_channel_id */
struct short_channel_id scid;
/* The ids of the nodes */
struct node_id id[2];
/* When we added, so we can discard old ones */
struct timeabs added;
/* If we loaded from the store, this is where. */
u32 index;
/* Channel capacity */
struct amount_sat sat;
};
static struct unupdated_channel *
get_unupdated_channel(const struct routing_state *rstate,
const struct short_channel_id *scid)
{
return uintmap_get(&rstate->unupdated_chanmap, scid->u64);
}
static void destroy_unupdated_channel(struct unupdated_channel *uc,
struct routing_state *rstate)
{
uintmap_del(&rstate->unupdated_chanmap, uc->scid.u64);
}
static struct node_map *empty_node_map(const tal_t *ctx)
{
struct node_map *map = tal(ctx, struct node_map);
@ -163,6 +193,7 @@ struct routing_state *new_routing_state(const tal_t *ctx,
rstate->local_channel_announced = false;
list_head_init(&rstate->pending_cannouncement);
uintmap_init(&rstate->chanmap);
uintmap_init(&rstate->unupdated_chanmap);
uintmap_init(&rstate->txout_failures);
rstate->pending_node_map = tal(ctx, struct pending_node_map);
@ -358,10 +389,6 @@ static void init_half_chan(struct routing_state *rstate,
// TODO: wireup message_flags
c->message_flags = 0;
broadcastable_init(&c->bcast);
/* We haven't seen channel_update: make it halfway to prune time,
* which should be older than any update we'd see. */
c->bcast.timestamp = gossip_time_now(rstate).ts.tv_sec - rstate->prune_timeout/2;
}
static void bad_gossip_order(const u8 *msg, const char *source,
@ -890,24 +917,15 @@ static bool is_local_channel(const struct routing_state *rstate,
static void add_channel_announce_to_broadcast(struct routing_state *rstate,
struct chan *chan,
u32 timestamp)
u32 timestamp,
u32 index)
{
chan->bcast.timestamp = timestamp;
/* 0, unless we're loading from store */
chan->bcast.index = index;
insert_broadcast(&rstate->broadcasts, chan->channel_announce,
&chan->bcast);
rstate->local_channel_announced |= is_local_channel(rstate, chan);
/* If we've been waiting for this, now we can announce node */
for (size_t i = 0; i < ARRAY_SIZE(chan->nodes); i++) {
struct node *node = chan->nodes[i];
if (!node->node_announcement)
continue;
if (!node->bcast.index) {
insert_broadcast(&rstate->broadcasts,
node->node_announcement,
&node->bcast);
}
}
}
bool routing_add_channel_announcement(struct routing_state *rstate,
@ -925,6 +943,8 @@ bool routing_add_channel_announcement(struct routing_state *rstate,
struct node_id node_id_2;
struct pubkey bitcoin_key_1;
struct pubkey bitcoin_key_2;
struct unupdated_channel *uc;
const u8 *private_updates[2] = { NULL, NULL };
/* Make sure we own msg, even if we don't save it. */
if (taken(msg))
@ -940,34 +960,42 @@ bool routing_add_channel_announcement(struct routing_state *rstate,
* local_add_channel(); normally we don't accept new
* channel_announcements. See handle_channel_announcement. */
chan = get_channel(rstate, &scid);
if (!chan)
chan = new_chan(rstate, &scid, &node_id_1, &node_id_2, sat);
/* Channel is now public. */
chan->channel_announce = tal_dup_arr(chan, u8, msg, tal_count(msg), 0);
/* If we're loading from the store, save index now */
chan->bcast.index = index;
/* This is filled in when we get a channel_update */
chan->bcast.timestamp = 0;
/* Apply any private updates. */
for (size_t i = 0; i < ARRAY_SIZE(chan->half); i++) {
const u8 *update = chan->half[i].channel_update;
if (!update)
continue;
/* Remove from channel, otherwise it will be freed! */
chan->half[i].channel_update = NULL;
/* If we loaded from store, index will be non-zero */
routing_add_channel_update(rstate, take(update),
chan->half[i].bcast.index);
}
/* If we were waiting for these nodes to appear (or gain a
public channel), process node_announcements now */
process_pending_node_announcement(rstate, &chan->nodes[0]->id);
process_pending_node_announcement(rstate, &chan->nodes[1]->id);
/* private updates will exist in the store before the announce: we
* can't index those for broadcast since they would predate it, so we
* add fresh ones. But if we're loading off disk right now, we can't
* do that. */
if (chan && index == 0) {
/* Steal any private updates */
private_updates[0]
= tal_steal(NULL, chan->half[0].channel_update);
private_updates[1]
= tal_steal(NULL, chan->half[1].channel_update);
}
/* Pretend it didn't exist, for the moment. */
tal_free(chan);
uc = tal(rstate, struct unupdated_channel);
uc->channel_announce = tal_dup_arr(uc, u8, msg, tal_count(msg), 0);
uc->added = time_now();
uc->index = index;
uc->sat = sat;
uc->scid = scid;
uc->id[0] = node_id_1;
uc->id[1] = node_id_2;
uintmap_add(&rstate->unupdated_chanmap, scid.u64, uc);
tal_add_destructor2(uc, destroy_unupdated_channel, rstate);
/* If a node_announcement comes along, save it for once we're updated */
catch_node_announcement(uc, rstate, &node_id_1);
catch_node_announcement(uc, rstate, &node_id_2);
/* If we had private updates, they'll immediately create the channel. */
if (private_updates[0])
routing_add_channel_update(rstate, take(private_updates[0]), 0);
if (private_updates[1])
routing_add_channel_update(rstate, take(private_updates[1]), 0);
return true;
}
@ -1030,6 +1058,13 @@ u8 *handle_channel_announcement(struct routing_state *rstate,
&pending->short_channel_id));
goto ignored;
}
if (get_unupdated_channel(rstate, &pending->short_channel_id)) {
SUPERVERBOSE("%s: %s already has unupdated channel",
__func__,
type_to_string(tmpctx, struct short_channel_id,
&pending->short_channel_id));
goto ignored;
}
/* We don't replace previous ones, since we might validate that and
* think this one is OK! */
@ -1270,7 +1305,6 @@ static void set_connection_values(struct chan *chan,
bool routing_add_channel_update(struct routing_state *rstate,
const u8 *update TAKES,
u32 index)
{
secp256k1_ecdsa_signature signature;
struct short_channel_id short_channel_id;
@ -1283,7 +1317,9 @@ bool routing_add_channel_update(struct routing_state *rstate,
struct bitcoin_blkid chain_hash;
struct chan *chan;
struct half_chan *hc;
struct unupdated_channel *uc;
u8 direction;
struct amount_sat sat;
/* Make sure we own msg, even if we don't save it. */
if (taken(update))
@ -1309,24 +1345,41 @@ bool routing_add_channel_update(struct routing_state *rstate,
direction = channel_flags & 0x1;
chan = get_channel(rstate, &short_channel_id);
if (!chan)
if (chan) {
uc = NULL;
sat = chan->sat;
} else {
/* Maybe announcement was waiting for this update? */
uc = get_unupdated_channel(rstate, &short_channel_id);
if (!uc) {
return false;
}
sat = uc->sat;
}
if (message_flags & ROUTING_OPT_HTLC_MAX_MSAT) {
/* Reject update if the `htlc_maximum_msat` is greater
* than the total available channel satoshis */
if (amount_msat_greater_sat(htlc_maximum, chan->sat))
if (amount_msat_greater_sat(htlc_maximum, sat))
return false;
} else {
/* If not indicated, set htlc_max_msat to channel capacity */
if (!amount_sat_to_msat(&htlc_maximum, chan->sat)) {
if (!amount_sat_to_msat(&htlc_maximum, sat)) {
status_broken("Channel capacity %s overflows!",
type_to_string(tmpctx, struct amount_sat,
&chan->sat));
&sat));
return false;
}
}
/* OK, we're going to accept this, so create chan if doesn't exist */
if (uc) {
assert(!chan);
chan = new_chan(rstate, &short_channel_id,
&uc->id[0], &uc->id[1], sat);
}
/* Discard older updates */
hc = &chan->half[direction];
if (is_halfchan_defined(hc) && timestamp <= hc->bcast.timestamp) {
@ -1366,33 +1419,44 @@ bool routing_add_channel_update(struct routing_state *rstate,
chan->half[direction].channel_update
= tal_dup_arr(chan, u8, update, tal_count(update), 0);
/* If we're loading from store, this means we don't re-add to store */
chan->half[direction].bcast.index = index;
/* BOLT #7:
* - MUST consider the `timestamp` of the `channel_announcement` to be
* the `timestamp` of a corresponding `channel_update`.
* - MUST consider whether to send the `channel_announcement` after
* receiving the first corresponding `channel_update`.
*/
if (uc) {
chan->channel_announce = tal_steal(chan, uc->channel_announce);
add_channel_announce_to_broadcast(rstate, chan, timestamp,
uc->index);
} else if (!chan->channel_announce) {
/* For private channels, we get updates without an announce: don't
* broadcast them! But save local ones to store anyway. */
if (!chan->channel_announce) {
struct half_chan *hc = &chan->half[direction];
/* Don't save if we're loading from store */
if (is_local_channel(rstate, chan) && !hc->bcast.index) {
if (is_local_channel(rstate, chan) && !index) {
hc->bcast.index = gossip_store_add(rstate->broadcasts->gs,
hc->channel_update);
}
} else
hc->bcast.index = index;
return true;
}
/* BOLT #7:
* - MUST consider the `timestamp` of the `channel_announcement` to be
* the `timestamp` of a corresponding `channel_update`.
* - MUST consider whether to send the `channel_announcement` after
* receiving the first corresponding `channel_update`.
*/
if (chan->bcast.timestamp == 0)
add_channel_announce_to_broadcast(rstate, chan, timestamp);
/* If we're loading from store, this means we don't re-add to store. */
chan->half[direction].bcast.index = index;
insert_broadcast(&rstate->broadcasts,
chan->half[direction].channel_update,
&chan->half[direction].bcast);
if (uc) {
/* If we were waiting for these nodes to appear (or gain a
public channel), process node_announcements now */
process_pending_node_announcement(rstate, &chan->nodes[0]->id);
process_pending_node_announcement(rstate, &chan->nodes[1]->id);
tal_free(uc);
}
return true;
}
@ -1401,9 +1465,15 @@ static const struct node_id *get_channel_owner(struct routing_state *rstate,
int direction)
{
struct chan *chan = get_channel(rstate, scid);
struct unupdated_channel *uc;
if (chan)
return &chan->nodes[direction]->id;
/* Might be unupdated channel */
uc = get_unupdated_channel(rstate, scid);
if (uc)
return &uc->id[direction];
return NULL;
}
@ -1573,8 +1643,11 @@ bool routing_add_node_announcement(struct routing_state *rstate,
/* May happen if we accepted the node_announcement due to a local
* channel, for which we didn't have the announcement yet. */
if (node == NULL)
if (node == NULL) {
if (taken(msg))
tal_free(msg);
return false;
}
tal_free(node->node_announcement);
/* Harmless if it was never added */
@ -1910,6 +1983,7 @@ void route_prune(struct routing_state *rstate)
const s64 highwater = now - rstate->prune_timeout;
const tal_t *pruned = tal(NULL, char);
struct chan *chan;
struct unupdated_channel *uc;
u64 idx;
/* Now iterate through all channels and see if it is still alive */
@ -1920,22 +1994,33 @@ void route_prune(struct routing_state *rstate)
if (!is_chan_public(chan))
continue;
/* Rare case where we examine timestamp even without update;
* it's used to prune channels where update never arrives */
if (chan->half[0].bcast.timestamp < highwater
&& chan->half[1].bcast.timestamp < highwater) {
if ((!is_halfchan_defined(&chan->half[0])
|| chan->half[0].bcast.timestamp < highwater)
&& (!is_halfchan_defined(&chan->half[1])
|| chan->half[1].bcast.timestamp < highwater)) {
status_trace(
"Pruning channel %s from network view (ages %"PRIu64" and %"PRIu64"s)",
type_to_string(tmpctx, struct short_channel_id,
&chan->scid),
now - chan->half[0].bcast.timestamp,
now - chan->half[1].bcast.timestamp);
is_halfchan_defined(&chan->half[0]) ? 0
: now - chan->half[0].bcast.timestamp,
is_halfchan_defined(&chan->half[1]) ? 0
: now - chan->half[1].bcast.timestamp);
/* This may perturb iteration so do outside loop. */
tal_steal(pruned, chan);
}
}
/* Look for channels we had an announcement for, but no update. */
for (uc = uintmap_first(&rstate->unupdated_chanmap, &idx);
uc;
uc = uintmap_after(&rstate->unupdated_chanmap, &idx)) {
if (uc->added.ts.tv_sec < highwater) {
tal_steal(pruned, uc);
}
}
/* This frees all the chans and maybe even nodes. */
tal_free(pruned);
}

5
gossipd/routing.h

@ -157,6 +157,7 @@ HTABLE_DEFINE_TYPE(struct node, node_map_keyof_node, node_map_hash_key, node_map
struct pending_node_map;
struct pending_cannouncement;
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,
@ -213,6 +214,10 @@ struct routing_state {
/* A map of channels indexed by short_channel_ids */
UINTMAP(struct chan *) chanmap;
/* A map of channel_announcements indexed by short_channel_ids:
* we haven't got a channel_update for these yet. */
UINTMAP(struct unupdated_channel *) unupdated_chanmap;
/* Has one of our own channels been announced? */
bool local_channel_announced;

Loading…
Cancel
Save