From 9c254c83870fd7e6e26862154c019cbc4272b0a5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 7 Oct 2021 14:27:14 +1030 Subject: [PATCH] gossipd: when we refresh channel, don't override pending updates. We can have an update pending because it's too fast, but refresh_local_channel is supposed to make sure we're up-to-date, so force immediate application in that case. Otherwise, we call update_local_channel at the bottom which frees the pending update. This can mean that we miss a change in fees, for example. Changelog-Fixed: errors: Errors returning a `channel_update` no longer return an outdated one. Signed-off-by: Rusty Russell --- gossipd/gossip_generation.c | 15 ++++++++++++++- gossipd/test/run-check_node_announcement.c | 3 +++ gossipd/test/run-crc32_of_update.c | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index f74db6634..4ca12da62 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -314,6 +314,7 @@ struct local_cupdate { bool disable; bool even_if_identical; + bool even_if_too_soon; u16 cltv_expiry_delta; struct amount_msat htlc_minimum, htlc_maximum; @@ -409,7 +410,7 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) next = hc->bcast.timestamp + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); - if (timestamp < next) { + 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, @@ -503,10 +504,21 @@ void refresh_local_channel(struct daemon *daemon, if (!is_halfchan_defined(hc)) return; + /* 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); + } + 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; prev = cast_const(u8 *, gossip_store_get(tmpctx, daemon->rstate->gs, @@ -546,6 +558,7 @@ bool handle_local_channel_update(struct daemon *daemon, lc->daemon = daemon; lc->even_if_identical = false; + lc->even_if_too_soon = false; /* FIXME: We should get scid from lightningd when setting up the * connection, so no per-peer daemon can mess with channels other than diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c index dd2202d7c..c4a9818ec 100644 --- a/gossipd/test/run-check_node_announcement.c +++ b/gossipd/test/run-check_node_announcement.c @@ -68,6 +68,9 @@ void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) /* Generated stub for queue_peer_msg */ void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) { fprintf(stderr, "queue_peer_msg called!\n"); abort(); } +/* Generated stub for reltimer_arg */ +void *reltimer_arg(struct oneshot *t UNNEEDED) +{ fprintf(stderr, "reltimer_arg called!\n"); abort(); } /* Generated stub for status_failed */ void status_failed(enum status_failreason code UNNEEDED, const char *fmt UNNEEDED, ...) diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 2f51c910c..82033c8d3 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -107,6 +107,9 @@ void queue_peer_from_store(struct peer *peer UNNEEDED, /* Generated stub for queue_peer_msg */ void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) { fprintf(stderr, "queue_peer_msg called!\n"); abort(); } +/* Generated stub for reltimer_arg */ +void *reltimer_arg(struct oneshot *t UNNEEDED) +{ fprintf(stderr, "reltimer_arg called!\n"); abort(); } /* Generated stub for status_failed */ void status_failed(enum status_failreason code UNNEEDED, const char *fmt UNNEEDED, ...)