Skip to content

Commit 4c4f6d9

Browse files
authored
Fluffy: Use neighboursInRange in neighborhoodGossip and filter out src node in handleFindContent (#3273)
1 parent 9d896dc commit 4c4f6d9

File tree

2 files changed

+51
-22
lines changed

2 files changed

+51
-22
lines changed

fluffy/network/wire/portal_protocol.nim

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,6 @@ func getNode*(p: PortalProtocol, id: NodeId): Opt[Node] =
360360
func localNode*(p: PortalProtocol): Node =
361361
p.baseProtocol.localNode
362362

363-
template neighbours*(
364-
p: PortalProtocol, id: NodeId, k: int = BUCKET_SIZE, seenOnly = false
365-
): seq[Node] =
366-
p.routingTable.neighbours(id, k, seenOnly)
367-
368363
func distance(p: PortalProtocol, a, b: NodeId): UInt256 =
369364
p.routingTable.distance(a, b)
370365

@@ -380,6 +375,34 @@ func inRange(
380375
template inRange*(p: PortalProtocol, contentId: ContentId): bool =
381376
p.inRange(p.localNode.id, p.dataRadius(), contentId)
382377

378+
func neighbours*(
379+
p: PortalProtocol,
380+
id: NodeId,
381+
k: int = BUCKET_SIZE,
382+
seenOnly = false,
383+
excluding = initHashSet[NodeId](),
384+
): seq[Node] =
385+
func nodeNotExcluded(nodeId: NodeId): bool =
386+
not excluding.contains(nodeId)
387+
388+
p.routingTable.neighbours(id, k, seenOnly, nodeNotExcluded)
389+
390+
func neighboursInRange*(
391+
p: PortalProtocol,
392+
id: ContentId,
393+
k: int = BUCKET_SIZE,
394+
seenOnly = false,
395+
excluding = initHashSet[NodeId](),
396+
): seq[Node] =
397+
func nodeNotExcludedAndInRange(nodeId: NodeId): bool =
398+
if excluding.contains(nodeId):
399+
return false
400+
let radius = p.radiusCache.get(nodeId).valueOr:
401+
return false
402+
p.inRange(nodeId, radius, id)
403+
404+
p.routingTable.neighbours(id, k, seenOnly, nodeNotExcludedAndInRange)
405+
383406
func truncateEnrs(
384407
nodes: seq[Node], maxSize: int, enrOverhead: int
385408
): List[ByteList[2048], 32] =
@@ -542,8 +565,10 @@ proc handleFindContent(
542565

543566
# Node does not have the content, or content is not even in radius,
544567
# send closest neighbours to the requested content id.
568+
545569
let
546-
closestNodes = p.neighbours(NodeId(contentId), seenOnly = true)
570+
closestNodes =
571+
p.neighbours(contentId, seenOnly = true, excluding = toHashSet([srcId]))
547572
enrs = truncateEnrs(closestNodes, maxPayloadSize, enrOverhead)
548573
portal_content_enrs_packed.observe(enrs.len().int64, labelValues = [$p.protocolId])
549574

@@ -1751,28 +1776,24 @@ proc neighborhoodGossip*(
17511776
# table, but at the same time avoid unnecessary node lookups.
17521777
# It might still cause issues in data getting propagated in a wider id range.
17531778

1779+
var excluding: HashSet[NodeId]
1780+
if srcNodeId.isSome():
1781+
excluding.incl(srcNodeId.get())
1782+
17541783
var closestLocalNodes =
1755-
p.routingTable.neighbours(NodeId(contentId), BUCKET_SIZE, seenOnly = true)
1784+
p.neighboursInRange(contentId, BUCKET_SIZE, seenOnly = true, excluding)
17561785

17571786
# Shuffling the order of the nodes in order to not always hit the same node
17581787
# first for the same request.
17591788
p.baseProtocol.rng[].shuffle(closestLocalNodes)
17601789

1761-
var gossipNodes: seq[Node]
1762-
for node in closestLocalNodes:
1763-
let radius = p.radiusCache.get(node.id).valueOr:
1764-
continue
1765-
if p.inRange(node.id, radius, contentId):
1766-
if srcNodeId.isNone() or node.id != srcNodeId.get():
1767-
gossipNodes.add(node)
1768-
17691790
var numberOfGossipedNodes = 0
17701791

1771-
if not enableNodeLookup or gossipNodes.len() >= p.config.maxGossipNodes:
1792+
if not enableNodeLookup or closestLocalNodes.len() >= p.config.maxGossipNodes:
17721793
# use local nodes for gossip
17731794
portal_gossip_without_lookup.inc(labelValues = [$p.protocolId])
17741795

1775-
for node in gossipNodes:
1796+
for node in closestLocalNodes:
17761797
let req = OfferRequest(dst: node, kind: Direct, contentList: contentList)
17771798
await p.offerQueue.addLast(req)
17781799
inc numberOfGossipedNodes

fluffy/tests/wire_protocol_tests/test_portal_wire_protocol.nim

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,24 @@ procSuite "Portal Wire Protocol Tests":
157157
await proto2.stopPortalProtocol()
158158

159159
asyncTest "FindContent/Content - send enrs":
160-
let (proto1, proto2) = defaultTestSetup(rng)
160+
let
161+
proto1 = initPortalProtocol(rng, PrivateKey.random(rng[]), localAddress(20402))
162+
proto2 = initPortalProtocol(rng, PrivateKey.random(rng[]), localAddress(20403))
163+
proto3 = initPortalProtocol(rng, PrivateKey.random(rng[]), localAddress(20404))
164+
165+
# Make node1 know about node2, and node2 about node3
166+
check proto1.addNode(proto2.localNode) == Added
167+
check proto2.addNode(proto3.localNode) == Added
161168

162-
# ping in one direction to add, ping in the other to update as seen.
163-
check (await proto1.baseProtocol.ping(proto2.localNode)).isOk()
164-
check (await proto2.baseProtocol.ping(proto1.localNode)).isOk()
169+
# node1 needs to know the radius of the nodes to determine if they are
170+
# interested in content, so a ping is done.
171+
check (await proto1.ping(proto2.localNode)).isOk()
172+
check (await proto2.ping(proto3.localNode)).isOk()
165173

166174
let contentKey = ContentKeyByteList.init(@[1'u8])
167175

168176
# content does not exist so this should provide us with the closest nodes
169-
# to the content, which is the only node in the routing table.
177+
# to the content, which should only be node 3 because node 1 should be excluded
170178
let content = await proto1.findContentImpl(proto2.localNode, contentKey)
171179

172180
check:

0 commit comments

Comments
 (0)