Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connectd: fix and further enhance our own gossip promotion #5200

4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This release named by Simon Vrouwe; this marks the name change to core-lightning

- Protocol: we now support opening multiple channels with the same peer. ([#5078])
- Protocol: we send/receive IP addresses in `init`, and send updated node_announcement when two peers report the same remote_addr (`disable-ip-discovery` suppresses this announcement). ([#5052])
- Protocol: we more aggressively send our own gossip, to improve propagation chances. ([#5200])
- Plugins: `cln-grpc` first class GRPC interface for remotely controlling nodes over mTLS authentication; set `grpc-port` to activate ([#5013])
- Database: With the `sqlite3://` scheme for `--wallet` option, you can now specify a second file path for real-time database backup by separating it from the main file path with a `:` character. ([#4890])
- Protocol: `pay` (and decode, etc) supports bolt11 payment_metadata a-la https://github.com/lightning/bolts/pull/912 ([#5086])
Expand Down Expand Up @@ -96,7 +97,7 @@ Note: You should always set `allow-deprecated-apis=false` to test for changes.
- Fixed `experimental-websocket-port` to work with default addresses. ([#4945])
- Protocol: removed support for v0.10.1 onion messages. ([#4921])
- Protocol: Ability to announce DNS addresses ([#4829])

- Protocol: disabled websocket announcement due to LND propagation issues ([#5200])


[#4829]: https://github.com/ElementsProject/lightning/pull/4829
Expand Down Expand Up @@ -141,6 +142,7 @@ Note: You should always set `allow-deprecated-apis=false` to test for changes.
[#5130]: https://github.com/ElementsProject/lightning/pull/5130
[#5136]: https://github.com/ElementsProject/lightning/pull/5136
[#5146]: https://github.com/ElementsProject/lightning/pull/5146
[#5200]: https://github.com/ElementsProject/lightning/pull/5200
[0.11.0]: https://github.com/ElementsProject/lightning/releases/tag/v0.11.0

## [0.10.2] - 2021-11-03: Bitcoin Dust Consensus Rule
Expand Down
3 changes: 3 additions & 0 deletions common/gossip_store.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static size_t reopen_gossip_store(int *gossip_store_fd, const u8 *msg)
u8 *gossip_store_next(const tal_t *ctx,
int *gossip_store_fd,
u32 timestamp_min, u32 timestamp_max,
bool push_only,
size_t *off, size_t *end)
{
u8 *msg = NULL;
Expand Down Expand Up @@ -109,6 +110,8 @@ u8 *gossip_store_next(const tal_t *ctx,
!timestamp_filter(timestamp_min, timestamp_max,
timestamp)) {
msg = tal_free(msg);
} else if (!push && push_only) {
msg = tal_free(msg);
}
}

Expand Down
1 change: 1 addition & 0 deletions common/gossip_store.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct gossip_hdr {
u8 *gossip_store_next(const tal_t *ctx,
int *gossip_store_fd,
u32 timestamp_min, u32 timestamp_max,
bool push_only,
size_t *off, size_t *end);

/**
Expand Down
14 changes: 10 additions & 4 deletions connectd/connectd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1397,10 +1397,15 @@ setup_listeners(const tal_t *ctx,
* different type.
*/
if (tal_count(*announceable) != 0) {
wireaddr_from_websocket(&addr.u.wireaddr,
daemon->websocket_port);
add_announceable(announceable,
&addr.u.wireaddr);
/* See https://github.com/lightningnetwork/lnd/issues/6432:
* if we add websocket to the node_announcement, it doesn't propagate.
* So we do not do this for now in general! */
if (daemon->announce_websocket) {
wireaddr_from_websocket(&addr.u.wireaddr,
daemon->websocket_port);
add_announceable(announceable,
&addr.u.wireaddr);
}
} else {
status_unusual("Bound to websocket %s,"
" but we cannot announce"
Expand Down Expand Up @@ -1535,6 +1540,7 @@ static void connect_init(struct daemon *daemon, const u8 *msg)
&daemon->timeout_secs,
&daemon->websocket_helper,
&daemon->websocket_port,
&daemon->announce_websocket,
&dev_fast_gossip,
&dev_disconnect,
&dev_no_ping_timer)) {
Expand Down
3 changes: 3 additions & 0 deletions connectd/connectd.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ struct daemon {
int gossip_store_fd;
size_t gossip_store_end;

/* We only announce websocket addresses if !deprecated_apis */
bool announce_websocket;

#if DEVELOPER
/* Hack to speed up gossip timer */
bool dev_fast_gossip;
Expand Down
1 change: 1 addition & 0 deletions connectd/connectd_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ msgdata,connectd_init,use_v3_autotor,bool,
msgdata,connectd_init,timeout_secs,u32,
msgdata,connectd_init,websocket_helper,wirestring,
msgdata,connectd_init,websocket_port,u16,
msgdata,connectd_init,announce_websocket,bool,
msgdata,connectd_init,dev_fast_gossip,bool,
# If this is set, then fd 5 is dev_disconnect_fd.
msgdata,connectd_init,dev_disconnect,bool,
Expand Down
30 changes: 24 additions & 6 deletions connectd/multiplex.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,27 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer)
{
u8 *msg;

/* Not streaming yet? */
/* dev-mode can suppress all gossip */
if (IFDEV(peer->daemon->dev_suppress_gossip, false))
return NULL;

/* BOLT #7:
* - if the `gossip_queries` feature is negotiated:
* - MUST NOT relay any gossip messages it did not generate itself,
* unless explicitly requested.
*/

/* So, even if they didn't send us a timestamp_filter message,
* we *still* send our own gossip. */
if (!peer->gs.gossip_timer) {
return gossip_store_next(ctx, &peer->daemon->gossip_store_fd,
0, 0xFFFFFFFF,
true,
&peer->gs.off,
&peer->daemon->gossip_store_end);
}

/* Not streaming right now? */
if (!peer->gs.active)
return NULL;

Expand All @@ -367,13 +387,11 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer)
msg = gossip_store_next(ctx, &peer->daemon->gossip_store_fd,
peer->gs.timestamp_min,
peer->gs.timestamp_max,
false,
&peer->gs.off,
&peer->daemon->gossip_store_end);
/* Don't send back gossip they sent to us! */
if (msg) {
status_peer_debug(&peer->id,
"Sending gossip %s",
peer_wire_name(fromwire_peektype(msg)));
if (gossip_rcvd_filter_del(peer->gs.grf, msg)) {
msg = tal_free(msg);
goto again;
Expand Down Expand Up @@ -561,7 +579,7 @@ static void handle_gossip_in(struct peer *peer, const u8 *msg)
daemon_conn_send(peer->daemon->gossipd, take(gmsg));
}

static void handle_gossip_timetamp_filter_in(struct peer *peer, const u8 *msg)
static void handle_gossip_timestamp_filter_in(struct peer *peer, const u8 *msg)
{
struct bitcoin_blkid chain_hash;
u32 first_timestamp, timestamp_range;
Expand Down Expand Up @@ -629,7 +647,7 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg)
gossip_rcvd_filter_add(peer->gs.grf, msg);

if (type == WIRE_GOSSIP_TIMESTAMP_FILTER) {
handle_gossip_timetamp_filter_in(peer, msg);
handle_gossip_timestamp_filter_in(peer, msg);
return true;
} else if (type == WIRE_PING) {
handle_ping_in(peer, msg);
Expand Down
30 changes: 12 additions & 18 deletions gossipd/gossip_generation.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,19 +335,9 @@ static bool update_own_node_announcement(struct daemon *daemon,
return true;
}

/* This retransmits the existing node announcement */
static void force_self_nannounce_rexmit(struct daemon *daemon)
{
struct node *self = get_node(daemon->rstate, &daemon->id);

force_node_announce_rexmit(daemon->rstate, self);
}

static void update_own_node_announcement_after_startup(struct daemon *daemon)
{
/* If that doesn't send one, arrange rexmit anyway */
if (!update_own_node_announcement(daemon, false, false))
force_self_nannounce_rexmit(daemon);
update_own_node_announcement(daemon, false, false);
}

/* This creates and transmits a *new* node announcement */
Expand All @@ -362,15 +352,23 @@ static void force_self_nannounce_regen(struct daemon *daemon)
update_own_node_announcement(daemon, false, true);
}

/* Because node_announcement propagation is spotty, we rexmit this every
/* Because node_announcement propagation is spotty, we regenerate this every
* 24 hours. */
static void setup_force_nannounce_regen_timer(struct daemon *daemon)
{
struct timerel regen_time;

/* For developers we can force a regen every 24 seconds to test */
if (IFDEV(daemon->rstate->dev_fast_gossip_prune, false))
regen_time = time_from_sec(24);
else
regen_time = time_from_sec(24 * 3600);

tal_free(daemon->node_announce_regen_timer);
daemon->node_announce_regen_timer
= new_reltimer(&daemon->timers,
daemon,
time_from_sec(24 * 3600),
regen_time,
force_self_nannounce_regen,
daemon);
}
Expand All @@ -386,11 +384,7 @@ void maybe_send_own_node_announce(struct daemon *daemon, bool startup)
if (!daemon->rstate->local_channel_announced)
return;

/* If we didn't send one, arrange rexmit of existing at startup */
if (!update_own_node_announcement(daemon, startup, false)) {
if (startup)
force_self_nannounce_rexmit(daemon);
}
update_own_node_announcement(daemon, startup, false);
}

/* Fast accessors for channel_update fields */
Expand Down
10 changes: 6 additions & 4 deletions gossipd/routing.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,8 @@ static bool node_announce_predates_channels(const struct node *node)

/* Move this node's announcement to the tail of the gossip_store, to
* make everyone send it again. */
void force_node_announce_rexmit(struct routing_state *rstate,
struct node *node)
static void force_node_announce_rexmit(struct routing_state *rstate,
struct node *node)
{
const u8 *announce;
bool is_local = node_id_eq(&node->id, &rstate->local_id);
Expand Down Expand Up @@ -1614,6 +1614,7 @@ bool routing_add_node_announcement(struct routing_state *rstate,

if (node->bcast.index) {
bool only_tlv_diff;
u32 redundant_time;

if (index != 0) {
status_broken("gossip_store node_announcement %u replaces %u!",
Expand All @@ -1627,8 +1628,9 @@ bool routing_add_node_announcement(struct routing_state *rstate,
return index == 0;
}

/* Allow redundant updates once every 7 days */
if (timestamp < node->bcast.timestamp + GOSSIP_PRUNE_INTERVAL(rstate->dev_fast_gossip_prune) / 2
/* Allow redundant updates once a day (faster in dev-fast-gossip-prune mode) */
redundant_time = GOSSIP_PRUNE_INTERVAL(rstate->dev_fast_gossip_prune) / 14;
if (timestamp < node->bcast.timestamp + redundant_time
&& !nannounce_different(rstate->gs, node, msg,
&only_tlv_diff)) {
SUPERVERBOSE(
Expand Down
4 changes: 0 additions & 4 deletions gossipd/routing.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,4 @@ void remove_all_gossip(struct routing_state *rstate);
/* This scid is dead to us. */
void add_to_txout_failures(struct routing_state *rstate,
const struct short_channel_id *scid);

/* Move this node's announcement to the tail of the gossip_store, to
* make everyone send it again. */
void force_node_announce_rexmit(struct routing_state *rstate, struct node *node);
#endif /* LIGHTNING_GOSSIPD_ROUTING_H */
3 changes: 0 additions & 3 deletions gossipd/test/run-check_node_announcement.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
/* Generated stub for find_peer */
struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "find_peer called!\n"); abort(); }
/* Generated stub for force_node_announce_rexmit */
void force_node_announce_rexmit(struct routing_state *rstate UNNEEDED, struct node *node UNNEEDED)
{ fprintf(stderr, "force_node_announce_rexmit called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_local_channel_update */
bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct node_id *id UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); }
Expand Down
3 changes: 0 additions & 3 deletions gossipd/test/run-crc32_of_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
/* Generated stub for find_peer */
struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "find_peer called!\n"); abort(); }
/* Generated stub for force_node_announce_rexmit */
void force_node_announce_rexmit(struct routing_state *rstate UNNEEDED, struct node *node UNNEEDED)
{ fprintf(stderr, "force_node_announce_rexmit called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_dev_set_max_scids_encode_size */
bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); }
Expand Down
1 change: 1 addition & 0 deletions lightningd/connect_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ int connectd_init(struct lightningd *ld)
ld->config.connection_timeout_secs,
websocket_helper_path,
ld->websocket_port,
!deprecated_apis,
IFDEV(ld->dev_fast_gossip, false),
IFDEV(ld->dev_disconnect_fd >= 0, false),
IFDEV(ld->dev_no_ping_timer, false));
Expand Down
5 changes: 5 additions & 0 deletions tests/test_gossip.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def test_gossip_pruning(node_factory, bitcoind):
wait_for(lambda: [c['active'] for c in l2.rpc.listchannels()['channels']] == [True] * 4)
wait_for(lambda: [c['active'] for c in l3.rpc.listchannels()['channels']] == [True] * 4)

# Also check that it sends a redundant node_announcement.
ts1 = only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['last_timestamp']
wait_for(lambda: only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['last_timestamp'] != ts1)
assert only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['last_timestamp'] >= ts1 + 24

# All of them should send a keepalive message (after 30 seconds)
l1.daemon.wait_for_logs([
'Sending keepalive channel_update for {}'.format(scid1),
Expand Down