Add `GossipTimestampFilter` buffer during gossip queries to fix flaky tests (#3152)
What changed, and why it matters
This commit tweaks how Eclair nodes request network routing gossip from peers. It subtracts one minute from the starting timestamp filter so that very recent routing announcements that haven't yet reached the peer are still forwarded. The change is described by the authors as fixing flaky tests rather than a real-world security bug, and it slightly reduces the chance of a node missing fresh channel updates during sync.
No immediate security action required. Treat as a minor robustness improvement. If reviewing, confirm the 1-minute buffer does not meaningfully increase bandwidth or expose the node to stale gossip abuse; the commit message indicates this was considered unlikely.
Security signals we found
Routing/gossip synchronization logic changed
Timestamp filter boundary adjusted to include older recent messages
Commit message frames change as test reliability fix, not security vulnerability
Evidence from the diff
In Sync.scala, the initial GossipTimestampFilter sent to a peer is changed from firstTimestamp = now() to firstTimestamp = now() - 1.minute, with timestampRange = Int.MaxValue. The intent is to avoid a race where a channel update created just before the filter timestamp fails to propagate through an intermediate peer to the syncing node. The commit message explicitly calls this a test-flakiness fix and says the scenario is unlikely in production.
Changed components
eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scalaGossipTimestampFilter generation during peer syncInspect captured patch +3 / −2
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala
index 569d9b7..ee7f64d 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Sync.scala
@@ -31,6 +31,7 @@ import shapeless.HNil
import scala.annotation.tailrec
import scala.collection.SortedSet
import scala.collection.immutable.SortedMap
+import scala.concurrent.duration.DurationInt
import scala.util.Random
object Sync {
@@ -55,10 +56,10 @@ object Sync {
s.to ! query
// we also set a pass-all filter for now (we can update it later) for the future gossip messages, by setting
- // the first_timestamp field to the current date/time and timestamp_range to the maximum value
+ // the first_timestamp field to the current date/time minus one minute and timestamp_range to the maximum value
// NB: we can't just set firstTimestamp to 0, because in that case peer would send us all past messages matching
// that (i.e. the whole routing table)
- val filter = GossipTimestampFilter(s.chainHash, firstTimestamp = TimestampSecond.now(), timestampRange = Int.MaxValue)
+ val filter = GossipTimestampFilter(s.chainHash, firstTimestamp = TimestampSecond.now() - 1.minute, timestampRange = Int.MaxValue) // the one minute buffer ensures that we don't miss recent gossip that hasn't reached our peer yet
s.to ! filter
// reset our sync state for this peer: we create an entry to ensure we reject duplicate queries and unsolicited reply_channel_range
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.