fix(gossipsub): save iDontWants messages in the first element of history (#1393)

This commit is contained in:
Radosław Kamiński
2025-05-29 13:33:51 +01:00
committed by GitHub
parent 86695b55bb
commit e811c1ad32
3 changed files with 26 additions and 15 deletions

View File

@@ -305,9 +305,9 @@ proc handleIHave*(
proc handleIDontWant*(g: GossipSub, peer: PubSubPeer, iDontWants: seq[ControlIWant]) =
for dontWant in iDontWants:
for messageId in dontWant.messageIDs:
if peer.iDontWants[^1].len > 1000:
if peer.iDontWants[0].len > 1000:
break
peer.iDontWants[^1].incl(g.salt(messageId))
peer.iDontWants[0].incl(g.salt(messageId))
proc handleIWant*(
g: GossipSub, peer: PubSubPeer, iwants: seq[ControlIWant]

View File

@@ -443,7 +443,7 @@ suite "GossipSub Control Messages":
# Then B doesn't relay the message to C.
checkUntilTimeout:
nodes[1].mesh.getOrDefault(topic).anyIt(it.iDontWants[^1].len == 1)
nodes[1].mesh.getOrDefault(topic).anyIt(it.iDontWants.anyIt(it.len == 1))
# When A sends a message to the topic
tryPublish await nodes[0].publish(topic, newSeq[byte](10000)), 1
@@ -452,9 +452,9 @@ suite "GossipSub Control Messages":
# Then B sends IDONTWANT to C, but not A
checkUntilTimeout:
toSeq(nodes[2].mesh.getOrDefault(topic)).anyIt(it.iDontWants[^1].len == 1)
toSeq(nodes[2].mesh.getOrDefault(topic)).anyIt(it.iDontWants.anyIt(it.len == 1))
check:
toSeq(nodes[0].mesh.getOrDefault(topic)).anyIt(it.iDontWants[^1].len == 0)
toSeq(nodes[0].mesh.getOrDefault(topic)).allIt(it.iDontWants.allIt(it.len == 0))
asyncTest "IDONTWANT is broadcasted on publish":
# 2 nodes: A <=> B
@@ -476,7 +476,7 @@ suite "GossipSub Control Messages":
# Then IDONTWANT is sent to B on publish
checkUntilTimeout:
nodes[1].mesh.getOrDefault(topic).anyIt(it.iDontWants[^1].len == 1)
nodes[1].mesh.getOrDefault(topic).anyIt(it.iDontWants.anyIt(it.len == 1))
asyncTest "IDONTWANT is sent only for 1.2":
# 3 nodes: A <=> B <=> C (A & C are NOT connected)
@@ -510,5 +510,5 @@ suite "GossipSub Control Messages":
# Then B doesn't send IDONTWANT to both A and C (because C.gossipSubVersion == GossipSubCodec_11)
await waitForHeartbeat()
check:
toSeq(nodeC.mesh.getOrDefault(topic)).anyIt(it.iDontWants[^1].len == 0)
toSeq(nodeA.mesh.getOrDefault(topic)).anyIt(it.iDontWants[^1].len == 0)
toSeq(nodeC.mesh.getOrDefault(topic)).allIt(it.iDontWants.allIt(it.len == 0))
toSeq(nodeA.mesh.getOrDefault(topic)).allIt(it.iDontWants.allIt(it.len == 0))

View File

@@ -229,8 +229,8 @@ suite "GossipSub Heartbeat":
asyncTest "iDontWants history - last element is pruned during heartbeat":
const
topic = "foobar"
historyLength = 5
heartbeatInterval = 200.milliseconds
historyLength = 3
let nodes = generateNodes(
2,
gossip = true,
@@ -253,19 +253,30 @@ suite "GossipSub Heartbeat":
checkUntilCustomTimeout(timeout, interval):
peer.iDontWants.len == historyLength
# When Node0 sends 5 messages to the topic
# When Node0 sends 5 messages to the topic
const msgCount = 5
for i in 0 ..< msgCount:
tryPublish await nodes[0].publish(topic, newSeq[byte](1000)), 1
# Then Node1 receives 5 iDontWant messages from Node0
checkUntilCustomTimeout(timeout, interval):
peer.iDontWants[^1].len == msgCount
peer.iDontWants[0].len == msgCount
# When heartbeat happens
# Then last element of iDontWants history is pruned
checkUntilCustomTimeout(timeout, interval):
peer.iDontWants[^1].len == 0
for i in 0 ..< historyLength:
# When heartbeat happens
# And history moves (new element added at start, last element pruned)
checkUntilCustomTimeout(timeout, interval):
peer.iDontWants[i].len == 0
# Then iDontWant messages are moved to the next element
var expectedHistory = newSeqWith(historyLength, 0)
let nextIndex = i + 1
if nextIndex < historyLength:
expectedHistory[nextIndex] = msgCount
# Until they reach last element and are pruned
checkUntilCustomTimeout(timeout, interval):
peer.iDontWants.mapIt(it.len) == expectedHistory
asyncTest "sentIHaves history - last element is pruned during heartbeat":
# 3 Nodes, Node 0 <==> Node 1 and Node 0 <==> Node 2