mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
gossipd: delay generation of local updates.
We disable the channel every time the peer disconnects; if it reconnects we get two updates. The simplest solution: delay all updates by 15 seconds. Replace any pending delayed update. If update is redundant after 15 seconds, discard. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
55a09d79b9
commit
f9b8237d50
202
gossipd/gossip.c
202
gossipd/gossip.c
@ -106,6 +106,25 @@ HTABLE_DEFINE_TYPE(struct important_peerid,
|
||||
static u32 max_scids_encode_bytes = -1U;
|
||||
#endif
|
||||
|
||||
struct local_update {
|
||||
/* daemon->local_updates */
|
||||
struct list_node list;
|
||||
|
||||
/* Because we're handed to a one-arg timer */
|
||||
struct daemon *daemon;
|
||||
|
||||
/* Which channel this is */
|
||||
struct short_channel_id scid;
|
||||
|
||||
/* Which direction we own */
|
||||
int direction;
|
||||
|
||||
u16 cltv_delta;
|
||||
u64 htlc_minimum_msat;
|
||||
u32 fee_base_msat, fee_proportional_millionths;
|
||||
bool disable;
|
||||
};
|
||||
|
||||
struct daemon {
|
||||
/* Who am I? */
|
||||
struct pubkey id;
|
||||
@ -158,6 +177,9 @@ struct daemon {
|
||||
bool use_proxy_always;
|
||||
char *tor_password;
|
||||
|
||||
/* Unapplied local updates waiting for their timers. */
|
||||
struct list_head local_updates;
|
||||
|
||||
/* @see lightningd.config.use_dns */
|
||||
bool use_dns;
|
||||
|
||||
@ -1671,79 +1693,72 @@ static bool update_redundant(const struct half_chan *hc,
|
||||
&& hc->proportional_fee == fee_proportional_millionths;
|
||||
}
|
||||
|
||||
static void handle_local_channel_update(struct peer *peer, const u8 *msg)
|
||||
static struct local_update *find_local_update(struct daemon *daemon,
|
||||
const struct short_channel_id *scid)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
u16 cltv_delta;
|
||||
u64 htlc_minimum_msat;
|
||||
u32 fee_base_msat, fee_proportional_millionths;
|
||||
bool disable;
|
||||
struct chan *chan;
|
||||
int direction;
|
||||
u8 *cupdate, *err;
|
||||
const struct pubkey *my_id = &peer->daemon->rstate->local_id;
|
||||
struct local_update *i;
|
||||
|
||||
if (!fromwire_gossip_local_channel_update(msg, &scid, &disable,
|
||||
&cltv_delta,
|
||||
&htlc_minimum_msat,
|
||||
&fee_base_msat,
|
||||
&fee_proportional_millionths)) {
|
||||
status_broken("peer %s bad local_channel_update %s",
|
||||
type_to_string(tmpctx, struct pubkey, &peer->id),
|
||||
tal_hex(tmpctx, msg));
|
||||
return;
|
||||
list_for_each(&daemon->local_updates, i, list) {
|
||||
if (structeq(scid, &i->scid))
|
||||
return i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Frees local_update */
|
||||
static void apply_delayed_local_update(struct local_update *local_update)
|
||||
{
|
||||
struct chan *chan;
|
||||
const struct half_chan *hc;
|
||||
u8 *cupdate, *err;
|
||||
|
||||
/* Can theoretically happen if channel just closed. */
|
||||
chan = get_channel(peer->daemon->rstate, &scid);
|
||||
chan = get_channel(local_update->daemon->rstate, &local_update->scid);
|
||||
if (!chan) {
|
||||
status_trace("peer %s local_channel_update for unknown %s",
|
||||
type_to_string(tmpctx, struct pubkey, &peer->id),
|
||||
status_trace("Delayed local_channel_update for unknown %s",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&scid));
|
||||
&local_update->scid));
|
||||
tal_free(local_update);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pubkey_eq(&chan->nodes[0]->id, my_id))
|
||||
direction = 0;
|
||||
else if (pubkey_eq(&chan->nodes[1]->id, my_id))
|
||||
direction = 1;
|
||||
else {
|
||||
status_broken("peer %s bad local_channel_update for non-local %s",
|
||||
type_to_string(tmpctx, struct pubkey, &peer->id),
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&scid));
|
||||
return;
|
||||
}
|
||||
/* Convenience variable */
|
||||
hc = &chan->half[local_update->direction];
|
||||
|
||||
/* Avoid redundant updates on public channels: on non-public channels
|
||||
* we'd need to consider pending updates, so don't bother. */
|
||||
if (is_chan_public(chan)
|
||||
&& update_redundant(&chan->half[direction],
|
||||
disable, cltv_delta, htlc_minimum_msat,
|
||||
fee_base_msat, fee_proportional_millionths)) {
|
||||
&& update_redundant(hc,
|
||||
local_update->disable,
|
||||
local_update->cltv_delta,
|
||||
local_update->htlc_minimum_msat,
|
||||
local_update->fee_base_msat,
|
||||
local_update->fee_proportional_millionths)) {
|
||||
status_trace("Suppressing redundant channel update for %s:(%u) %s %"PRIu64"/%u vs %u/%u",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&scid),
|
||||
direction,
|
||||
is_halfchan_defined(&chan->half[direction])
|
||||
? (chan->half[direction].flags & ROUTING_FLAGS_DISABLED ? "DISABLED" : "ACTIVE")
|
||||
&local_update->scid),
|
||||
local_update->direction,
|
||||
is_halfchan_defined(hc)
|
||||
? (hc->flags & ROUTING_FLAGS_DISABLED ? "DISABLED" : "ACTIVE")
|
||||
: "UNDEFINED",
|
||||
chan->half[direction].last_timestamp,
|
||||
hc->last_timestamp,
|
||||
(u32)time_now().ts.tv_sec,
|
||||
chan->half[direction].flags, disable);
|
||||
hc->flags,
|
||||
local_update->disable);
|
||||
tal_free(local_update);
|
||||
return;
|
||||
}
|
||||
|
||||
cupdate = create_channel_update(tmpctx, peer->daemon->rstate,
|
||||
chan, direction,
|
||||
disable, cltv_delta,
|
||||
htlc_minimum_msat,
|
||||
fee_base_msat,
|
||||
fee_proportional_millionths);
|
||||
cupdate = create_channel_update(tmpctx, local_update->daemon->rstate,
|
||||
chan, local_update->direction,
|
||||
local_update->disable,
|
||||
local_update->cltv_delta,
|
||||
local_update->htlc_minimum_msat,
|
||||
local_update->fee_base_msat,
|
||||
local_update->fee_proportional_millionths);
|
||||
|
||||
err = handle_channel_update(peer->daemon->rstate, cupdate,
|
||||
"local_channel_update");
|
||||
err = handle_channel_update(local_update->daemon->rstate, cupdate,
|
||||
"apply_delayed_local_update");
|
||||
if (err)
|
||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"Rejected local channel update %s: %s",
|
||||
@ -1751,11 +1766,88 @@ static void handle_local_channel_update(struct peer *peer, const u8 *msg)
|
||||
tal_hex(tmpctx, err));
|
||||
|
||||
/* We always tell peer, even if it's not public yet */
|
||||
if (!is_chan_public(chan))
|
||||
queue_peer_msg(peer, take(cupdate));
|
||||
if (!is_chan_public(chan)) {
|
||||
struct peer *peer = find_peer(local_update->daemon,
|
||||
&chan->nodes[!local_update
|
||||
->direction]->id);
|
||||
if (peer)
|
||||
queue_peer_msg(peer, take(cupdate));
|
||||
}
|
||||
|
||||
status_trace("Channel update for %s(%u)%s",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&local_update->scid),
|
||||
local_update->direction,
|
||||
is_chan_public(chan) ? "" : " (private)");
|
||||
|
||||
/* That channel_update might trigger our first channel_announcement */
|
||||
maybe_send_own_node_announce(peer->daemon);
|
||||
maybe_send_own_node_announce(local_update->daemon);
|
||||
tal_free(local_update);
|
||||
}
|
||||
|
||||
static void destroy_local_update(struct local_update *local_update)
|
||||
{
|
||||
list_del_from(&local_update->daemon->local_updates,
|
||||
&local_update->list);
|
||||
}
|
||||
|
||||
static void handle_local_channel_update(struct peer *peer, const u8 *msg)
|
||||
{
|
||||
struct chan *chan;
|
||||
struct local_update *local_update;
|
||||
const struct pubkey *my_id = &peer->daemon->rstate->local_id;
|
||||
|
||||
local_update = tal(peer->daemon, struct local_update);
|
||||
local_update->daemon = peer->daemon;
|
||||
|
||||
if (!fromwire_gossip_local_channel_update(msg,
|
||||
&local_update->scid,
|
||||
&local_update->disable,
|
||||
&local_update->cltv_delta,
|
||||
&local_update->htlc_minimum_msat,
|
||||
&local_update->fee_base_msat,
|
||||
&local_update->fee_proportional_millionths)) {
|
||||
status_broken("peer %s bad local_channel_update %s",
|
||||
type_to_string(tmpctx, struct pubkey, &peer->id),
|
||||
tal_hex(tmpctx, msg));
|
||||
tal_free(local_update);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Can theoretically happen if channel just closed. */
|
||||
chan = get_channel(peer->daemon->rstate, &local_update->scid);
|
||||
if (!chan) {
|
||||
status_trace("peer %s local_channel_update for unknown %s",
|
||||
type_to_string(tmpctx, struct pubkey, &peer->id),
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&local_update->scid));
|
||||
tal_free(local_update);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pubkey_eq(&chan->nodes[0]->id, my_id))
|
||||
local_update->direction = 0;
|
||||
else if (pubkey_eq(&chan->nodes[1]->id, my_id))
|
||||
local_update->direction = 1;
|
||||
else {
|
||||
status_broken("peer %s bad local_channel_update for non-local %s",
|
||||
type_to_string(tmpctx, struct pubkey, &peer->id),
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&local_update->scid));
|
||||
tal_free(local_update);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free any old unapplied update. */
|
||||
tal_free(find_local_update(peer->daemon, &local_update->scid));
|
||||
|
||||
list_add_tail(&peer->daemon->local_updates, &local_update->list);
|
||||
tal_add_destructor(local_update, destroy_local_update);
|
||||
|
||||
/* Delay 1/4 a broadcast interval */
|
||||
new_reltimer(&peer->daemon->timers, local_update,
|
||||
time_from_msec(peer->daemon->broadcast_interval/4),
|
||||
apply_delayed_local_update, local_update);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2930,7 +3022,6 @@ static struct io_plan *gossip_init(struct daemon_conn *master,
|
||||
/* Now disable all local channels, they can't be connected yet. */
|
||||
gossip_disable_local_channels(daemon);
|
||||
|
||||
|
||||
new_reltimer(&daemon->timers, daemon,
|
||||
time_from_sec(daemon->rstate->prune_timeout/4),
|
||||
gossip_refresh_network, daemon);
|
||||
@ -3745,6 +3836,7 @@ int main(int argc, char *argv[])
|
||||
list_head_init(&daemon->reconnecting);
|
||||
list_head_init(&daemon->reaching);
|
||||
list_head_init(&daemon->addrhints);
|
||||
list_head_init(&daemon->local_updates);
|
||||
important_peerid_map_init(&daemon->important_peerids);
|
||||
timers_init(&daemon->timers, time_mono());
|
||||
daemon->broadcast_interval = 30000;
|
||||
|
Loading…
Reference in New Issue
Block a user