chore: add peer filtering by cluster for waku peer exchange (#2932)

This commit is contained in:
Simon-Pierre Vivier 2024-07-29 15:53:43 -04:00 committed by GitHub
parent e4e01fabfe
commit b4618f98ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 66 additions and 11 deletions

View File

@ -23,6 +23,8 @@ import
waku_relay, waku_relay,
waku_core, waku_core,
waku_core/message/codec, waku_core/message/codec,
common/enr/builder,
waku_enr/sharding,
], ],
../testlib/[wakucore, wakunode, simple_mock, assertions], ../testlib/[wakucore, wakunode, simple_mock, assertions],
./utils.nim ./utils.nim
@ -237,6 +239,39 @@ suite "Waku Peer Exchange":
response.isErr response.isErr
response.error == "peer_not_found_failure" response.error == "peer_not_found_failure"
asyncTest "Pool filtering":
let
key1 = generateSecp256k1Key()
key2 = generateSecp256k1Key()
cluster: Option[uint16] = some(uint16(16))
bindIp = parseIpAddress("0.0.0.0")
nodeTcpPort = Port(64010)
nodeUdpPort = Port(9000)
var
builder1 = EnrBuilder.init(key1)
builder2 = EnrBuilder.init(key2)
builder1.withIpAddressAndPorts(some(bindIp), some(nodeTcpPort), some(nodeUdpPort))
builder2.withIpAddressAndPorts(some(bindIp), some(nodeTcpPort), some(nodeUdpPort))
builder1.withShardedTopics(@["/waku/2/rs/1/7"]).expect("valid topic")
builder2.withShardedTopics(@["/waku/2/rs/16/32"]).expect("valid topic")
let
enr1 = builder1.build().expect("valid ENR")
enr2 = builder2.build().expect("valid ENR")
var
peerInfo1 = enr1.toRemotePeerInfo().expect("valid PeerInfo")
peerInfo2 = enr2.toRemotePeerInfo().expect("valid PeerInfo")
peerInfo1.origin = PeerOrigin.Discv5
peerInfo2.origin = PeerOrigin.Discv5
check:
not poolFilter(cluster, peerInfo1)
poolFilter(cluster, peerInfo2)
asyncTest "Request 0 peers, with 1 peer in PeerExchange": asyncTest "Request 0 peers, with 1 peer in PeerExchange":
# Given two valid nodes with PeerExchange # Given two valid nodes with PeerExchange
let let

View File

@ -341,7 +341,7 @@ proc setupProtocols(
# waku peer exchange setup # waku peer exchange setup
if conf.peerExchangeNode != "" or conf.peerExchange: if conf.peerExchangeNode != "" or conf.peerExchange:
try: try:
await mountPeerExchange(node) await mountPeerExchange(node, some(conf.clusterId))
except CatchableError: except CatchableError:
return return
err("failed to mount waku peer-exchange protocol: " & getCurrentExceptionMsg()) err("failed to mount waku peer-exchange protocol: " & getCurrentExceptionMsg())

View File

@ -1101,10 +1101,12 @@ proc mountRlnRelay*(
## Waku peer-exchange ## Waku peer-exchange
proc mountPeerExchange*(node: WakuNode) {.async: (raises: []).} = proc mountPeerExchange*(
node: WakuNode, cluster: Option[uint16] = none(uint16)
) {.async: (raises: []).} =
info "mounting waku peer exchange" info "mounting waku peer exchange"
node.wakuPeerExchange = WakuPeerExchange.new(node.peerManager) node.wakuPeerExchange = WakuPeerExchange.new(node.peerManager, cluster)
if node.started: if node.started:
try: try:

View File

@ -1,5 +1,5 @@
import import
std/[options, sequtils, random], std/[options, sequtils, random, sugar],
results, results,
chronicles, chronicles,
chronos, chronos,
@ -50,6 +50,7 @@ type
WakuPeerExchange* = ref object of LPProtocol WakuPeerExchange* = ref object of LPProtocol
peerManager*: PeerManager peerManager*: PeerManager
enrCache*: seq[enr.Record] enrCache*: seq[enr.Record]
cluster*: Option[uint16]
# todo: next step: ring buffer; future: implement cache satisfying https://rfc.vac.dev/spec/34/ # todo: next step: ring buffer; future: implement cache satisfying https://rfc.vac.dev/spec/34/
proc request*( proc request*(
@ -128,12 +129,25 @@ proc getEnrsFromCache(
# return numPeers or less if cache is smaller # return numPeers or less if cache is smaller
return shuffledCache[0 ..< min(shuffledCache.len.int, numPeers.int)] return shuffledCache[0 ..< min(shuffledCache.len.int, numPeers.int)]
proc poolFilter*(cluster: Option[uint16], peer: RemotePeerInfo): bool =
if peer.origin != Discv5:
trace "peer not from discv5", peer = $peer, origin = $peer.origin
return false
if peer.enr.isNone():
trace "peer has no ENR", peer = $peer
return false
if cluster.isSome() and peer.enr.get().isClusterMismatched(cluster.get()):
trace "peer has mismatching cluster", peer = $peer
return false
return true
proc populateEnrCache(wpx: WakuPeerExchange) = proc populateEnrCache(wpx: WakuPeerExchange) =
# share only peers that i) are reachable ii) come from discv5 # share only peers that i) are reachable ii) come from discv5 iii) share cluster
let withEnr = wpx.peerManager.peerStore let withEnr =
.getReachablePeers() wpx.peerManager.peerStore.getReachablePeers().filterIt(poolFilter(wpx.cluster, it))
.filterIt(it.origin == Discv5)
.filterIt(it.enr.isSome)
# either what we have or max cache size # either what we have or max cache size
var newEnrCache = newSeq[enr.Record](0) var newEnrCache = newSeq[enr.Record](0)
@ -181,8 +195,12 @@ proc initProtocolHandler(wpx: WakuPeerExchange) =
wpx.handler = handler wpx.handler = handler
wpx.codec = WakuPeerExchangeCodec wpx.codec = WakuPeerExchangeCodec
proc new*(T: type WakuPeerExchange, peerManager: PeerManager): T = proc new*(
let wpx = WakuPeerExchange(peerManager: peerManager) T: type WakuPeerExchange,
peerManager: PeerManager,
cluster: Option[uint16] = none(uint16),
): T =
let wpx = WakuPeerExchange(peerManager: peerManager, cluster: cluster)
wpx.initProtocolHandler() wpx.initProtocolHandler()
asyncSpawn wpx.updatePxEnrCache() asyncSpawn wpx.updatePxEnrCache()
return wpx return wpx