Skip to content

Commit

Permalink
gossipd: store and index most recent and last non-rate-limited gossip
Browse files Browse the repository at this point in the history
This grows the routing state in order to index both okay-to-broadcast
and rate-limited gossip. The gossip_store also logs the rate-limited
gossip if useful. This allows the broadcast of the last non-rate-limited
gossip.
  • Loading branch information
endothermicdev authored and rustyrussell committed Jul 6, 2022
1 parent 08a2b3b commit 87a66c1
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 37 deletions.
114 changes: 79 additions & 35 deletions gossipd/routing.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ static struct node *new_node(struct routing_state *rstate,
n->id = *id;
memset(n->chans.arr, 0, sizeof(n->chans.arr));
broadcastable_init(&n->bcast);
broadcastable_init(&n->rgraph);
n->tokens = TOKEN_MAX;
node_map_add(rstate->nodes, n);
tal_add_destructor2(n, destroy_node, rstate);
Expand Down Expand Up @@ -521,6 +522,7 @@ static void init_half_chan(struct routing_state *rstate,
struct half_chan *c = &chan->half[channel_idx];

broadcastable_init(&c->bcast);
broadcastable_init(&c->rgraph);
c->tokens = TOKEN_MAX;
}

Expand Down Expand Up @@ -1340,7 +1342,7 @@ bool routing_add_channel_update(struct routing_state *rstate,
return false;
}

if (timestamp <= hc->bcast.timestamp) {
if (timestamp <= hc->rgraph.timestamp) {
SUPERVERBOSE("Ignoring outdated update.");
/* Ignoring != failing */
return true;
Expand Down Expand Up @@ -1377,15 +1379,34 @@ bool routing_add_channel_update(struct routing_state *rstate,
} else {
spam = false;
}

chan->half[direction].bcast.timestamp = timestamp;

/* Safe even if was never added, but if it's a private channel it
* would be a WIRE_GOSSIP_STORE_PRIVATE_UPDATE. */
gossip_store_delete(rstate->gs, &hc->bcast,
is_chan_public(chan)
? WIRE_CHANNEL_UPDATE
: WIRE_GOSSIP_STORE_PRIVATE_UPDATE);
/* Routing graph always uses the latest message. */
hc->rgraph.timestamp = timestamp;
if (spam) {
/* Remove the prior spam update if it exists. */
if (hc->rgraph.index != hc->bcast.index) {
gossip_store_delete(rstate->gs, &hc->rgraph,
is_chan_public(chan)
? WIRE_CHANNEL_UPDATE
: WIRE_GOSSIP_STORE_PRIVATE_UPDATE);
}
} else {
/* Safe to broadcast */
hc->bcast.timestamp = timestamp;
/* Remove prior spam update if one exists. */
if (hc->rgraph.index != hc->bcast.index) {
/* Safe even if was never added, but if it's a
* private channel it would be a
* WIRE_GOSSIP_STORE_PRIVATE_UPDATE. */
gossip_store_delete(rstate->gs, &hc->rgraph,
is_chan_public(chan)
? WIRE_CHANNEL_UPDATE
: WIRE_GOSSIP_STORE_PRIVATE_UPDATE);
}
gossip_store_delete(rstate->gs, &hc->bcast,
is_chan_public(chan)
? WIRE_CHANNEL_UPDATE
: WIRE_GOSSIP_STORE_PRIVATE_UPDATE);
}

/* BOLT #7:
* - MUST consider the `timestamp` of the `channel_announcement` to be
Expand All @@ -1407,23 +1428,31 @@ bool routing_add_channel_update(struct routing_state *rstate,
hc->bcast.index
= gossip_store_add_private_update(rstate->gs,
update);
} else
/* No need to separately track spam for private
* channels. */
hc->rgraph.index = hc->bcast.index;
} else {
hc->bcast.index = index;
hc->rgraph.index = index;
}
return true;
}

/* If we're loading from store, this means we don't re-add to store. */
if (index)
hc->bcast.index = index;
else {
hc->bcast.index
= gossip_store_add(rstate->gs, update,
hc->bcast.timestamp,
if (index) {
if (!spam)
hc->bcast.index = index;
hc->rgraph.index = index;
} else {
hc->rgraph.index
= gossip_store_add(rstate->gs, update, timestamp,
local_direction(rstate, chan, NULL),
spam, NULL);
if (hc->bcast.timestamp > rstate->last_timestamp
&& hc->bcast.timestamp < time_now().ts.tv_sec)
rstate->last_timestamp = hc->bcast.timestamp;
if (!spam)
hc->bcast.index = hc->rgraph.index;

peer_supplied_good_gossip(peer, 1);
}
Expand Down Expand Up @@ -1653,7 +1682,7 @@ bool routing_add_node_announcement(struct routing_state *rstate,
return false;
}

if (node->bcast.timestamp >= timestamp) {
if (node->rgraph.timestamp >= timestamp) {
SUPERVERBOSE("Ignoring node announcement, it's outdated.");
/* OK unless we're loading from store */
return index == 0;
Expand Down Expand Up @@ -1691,26 +1720,41 @@ bool routing_add_node_announcement(struct routing_state *rstate,
spam = false;
}

/* Harmless if it was never added */
gossip_store_delete(rstate->gs,
&node->bcast,
WIRE_NODE_ANNOUNCEMENT);

node->bcast.timestamp = timestamp;
if (node->bcast.timestamp > rstate->last_timestamp
&& node->bcast.timestamp < time_now().ts.tv_sec)
rstate->last_timestamp = node->bcast.timestamp;
/* Routing graph always references the latest message. */
node->rgraph.timestamp = timestamp;
if (!spam) {
node->bcast.timestamp = timestamp;
/* remove prior spam update if one exists */
if (node->rgraph.index != node->bcast.index) {
/* Harmless if it was never added */
gossip_store_delete(rstate->gs, &node->rgraph,
WIRE_NODE_ANNOUNCEMENT);
}
gossip_store_delete(rstate->gs, &node->bcast,
WIRE_NODE_ANNOUNCEMENT);
/* Remove prior spam update. */
} else if (node->rgraph.index != node->bcast.index) {
gossip_store_delete(rstate->gs, &node->rgraph,
WIRE_NODE_ANNOUNCEMENT);
}

if (index)
node->bcast.index = index;
else {
node->bcast.index
= gossip_store_add(rstate->gs, msg,
node->bcast.timestamp,
/* Don't add to the store if it was loaded from the store. */
if (index) {
node->rgraph.index = index;
if (!spam)
node->bcast.index = index;
} else {
node->rgraph.index
= gossip_store_add(rstate->gs, msg, timestamp,
node_id_eq(&node_id,
&rstate->local_id),
spam,
NULL);
spam, NULL);
if (node->bcast.timestamp > rstate->last_timestamp
&& node->bcast.timestamp < time_now().ts.tv_sec)
rstate->last_timestamp = node->bcast.timestamp;
if (!spam)
node->bcast.index = node->rgraph.index;

peer_supplied_good_gossip(peer, 1);
}

Expand Down
10 changes: 9 additions & 1 deletion gossipd/routing.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ struct peer;
struct routing_state;

struct half_chan {
/* Timestamp and index into store file */
/* Timestamp and index into store file - safe to broadcast */
struct broadcastable bcast;

/* Most recent gossip for the routing graph - may be rate-limited and
* non-broadcastable. If there is no spam, rgraph == bcast. */
struct broadcastable rgraph;

/* Token bucket */
u8 tokens;
};
Expand Down Expand Up @@ -105,6 +109,10 @@ struct node {
/* Timestamp and index into store file */
struct broadcastable bcast;

/* Possibly spam flagged. Nonbroadcastable, but used for routing graph.
* If there is no current spam, rgraph == bcast. */
struct broadcastable rgraph;

/* Token bucket */
u8 tokens;

Expand Down
4 changes: 3 additions & 1 deletion tests/test_gossip.py
Original file line number Diff line number Diff line change
Expand Up @@ -1863,7 +1863,8 @@ def channel_fees(node):
'0102c479b7684b9db496b844f6925f4ffd8a27c5840a020d1b537623c1545dcd8e195776381bbf51213e541a853a4a49a0faf84316e7ccca5e7074901a96bbabe04e06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100015d77400201010006000000000000000000000014000003eb000000003b023380',
# timestamp=1568096259, fee_proportional_millionths=1004
'01024b866012d995d3d7aec7b7218a283de2d03492dbfa21e71dd546ec2e36c3d4200453420aa02f476f99c73fe1e223ea192f5fa544b70a8319f2a216f1513d503d06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100015d77400301010006000000000000000000000014000003ec000000003b023380',
# update 5 marks you as a nasty spammer, but we listen to you anyway now! fee_proportional_millionths=1005
# update 5 marks you as a nasty spammer, but the routing graph is
# updated with this even though the gossip is not broadcast.
'01025b5b5a0daed874ab02bd3356d38190ff46bbaf5f10db5067da70f3ca203480ca78059e6621c6143f3da4e454d0adda6d01a9980ed48e71ccd0c613af73570a7106226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100015d77400401010006000000000000000000000014000003ed000000003b023380'
],
timeout=TIMEOUT
Expand All @@ -1887,6 +1888,7 @@ def channel_fees(node):
check=True,
timeout=TIMEOUT,
stdout=subprocess.PIPE).stdout.decode('utf8')
assert("fee_proportional_millionths=1004" in decoded)
# Used in routing graph, but not passed to gossip peers.
assert("fee_proportional_millionths=1005" not in decoded)

Expand Down

0 comments on commit 87a66c1

Please sign in to comment.