mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-05 23:43:07 +00:00
segregate peer-exchange client and service implementation (#3523)
This commit is contained in:
parent
e4358c9718
commit
4379f9ec50
@ -78,11 +78,11 @@ suite "Waku Peer Exchange":
|
|||||||
check:
|
check:
|
||||||
node.peerManager.switch.peerStore.peers.len == 0
|
node.peerManager.switch.peerStore.peers.len == 0
|
||||||
res.error.status_code == SERVICE_UNAVAILABLE
|
res.error.status_code == SERVICE_UNAVAILABLE
|
||||||
res.error.status_desc == some("PeerExchange is not mounted")
|
res.error.status_desc == some("PeerExchangeClient is not mounted")
|
||||||
|
|
||||||
asyncTest "Node fetches with mounted peer exchange, but no peers":
|
asyncTest "Node fetches with mounted peer exchange, but no peers":
|
||||||
# Given a node with peer exchange mounted
|
# Given a node with peer exchange mounted
|
||||||
await node.mountPeerExchange()
|
await node.mountPeerExchangeClient()
|
||||||
|
|
||||||
# When a node fetches peers
|
# When a node fetches peers
|
||||||
let res = await node.fetchPeerExchangePeers(1)
|
let res = await node.fetchPeerExchangePeers(1)
|
||||||
@ -95,7 +95,7 @@ suite "Waku Peer Exchange":
|
|||||||
|
|
||||||
asyncTest "Node succesfully exchanges px peers with faked discv5":
|
asyncTest "Node succesfully exchanges px peers with faked discv5":
|
||||||
# Given both nodes mount peer exchange
|
# Given both nodes mount peer exchange
|
||||||
await allFutures([node.mountPeerExchange(), node2.mountPeerExchange()])
|
await allFutures([node.mountPeerExchangeClient(), node2.mountPeerExchange()])
|
||||||
check node.peerManager.switch.peerStore.peers.len == 0
|
check node.peerManager.switch.peerStore.peers.len == 0
|
||||||
|
|
||||||
# Mock that we discovered a node (to avoid running discv5)
|
# Mock that we discovered a node (to avoid running discv5)
|
||||||
@ -271,6 +271,7 @@ suite "Waku Peer Exchange with discv5":
|
|||||||
# Mount peer exchange
|
# Mount peer exchange
|
||||||
await node1.mountPeerExchange()
|
await node1.mountPeerExchange()
|
||||||
await node3.mountPeerExchange()
|
await node3.mountPeerExchange()
|
||||||
|
await node3.mountPeerExchangeClient()
|
||||||
|
|
||||||
let dialResponse =
|
let dialResponse =
|
||||||
await node3.dialForPeerExchange(node1.switch.peerInfo.toRemotePeerInfo())
|
await node3.dialForPeerExchange(node1.switch.peerInfo.toRemotePeerInfo())
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import
|
|||||||
waku_peer_exchange/rpc,
|
waku_peer_exchange/rpc,
|
||||||
waku_peer_exchange/rpc_codec,
|
waku_peer_exchange/rpc_codec,
|
||||||
waku_peer_exchange/protocol,
|
waku_peer_exchange/protocol,
|
||||||
|
waku_peer_exchange/client,
|
||||||
node/peer_manager,
|
node/peer_manager,
|
||||||
waku_core,
|
waku_core,
|
||||||
common/enr/builder,
|
common/enr/builder,
|
||||||
@ -145,7 +146,7 @@ suite "Waku Peer Exchange":
|
|||||||
|
|
||||||
# Start and mount peer exchange
|
# Start and mount peer exchange
|
||||||
await allFutures([node1.start(), node2.start()])
|
await allFutures([node1.start(), node2.start()])
|
||||||
await allFutures([node1.mountPeerExchange(), node2.mountPeerExchange()])
|
await allFutures([node1.mountPeerExchange(), node2.mountPeerExchangeClient()])
|
||||||
|
|
||||||
# Create connection
|
# Create connection
|
||||||
let connOpt = await node2.peerManager.dialPeer(
|
let connOpt = await node2.peerManager.dialPeer(
|
||||||
@ -168,10 +169,10 @@ suite "Waku Peer Exchange":
|
|||||||
node1.wakuPeerExchange.enrCache.add(enr2)
|
node1.wakuPeerExchange.enrCache.add(enr2)
|
||||||
|
|
||||||
# Request 2 peer from px. Test all request variants
|
# Request 2 peer from px. Test all request variants
|
||||||
let response1 = await node2.wakuPeerExchange.request(2)
|
let response1 = await node2.wakuPeerExchangeClient.request(2)
|
||||||
let response2 =
|
let response2 =
|
||||||
await node2.wakuPeerExchange.request(2, node1.peerInfo.toRemotePeerInfo())
|
await node2.wakuPeerExchangeClient.request(2, node1.peerInfo.toRemotePeerInfo())
|
||||||
let response3 = await node2.wakuPeerExchange.request(2, connOpt.get())
|
let response3 = await node2.wakuPeerExchangeClient.request(2, connOpt.get())
|
||||||
|
|
||||||
# Check the response or dont even continue
|
# Check the response or dont even continue
|
||||||
require:
|
require:
|
||||||
@ -213,7 +214,7 @@ suite "Waku Peer Exchange":
|
|||||||
await connOpt.get().close()
|
await connOpt.get().close()
|
||||||
|
|
||||||
# Request 2 peer from px
|
# Request 2 peer from px
|
||||||
let response = await node1.wakuPeerExchange.request(2, connOpt.get())
|
let response = await node1.wakuPeerExchangeClient.request(2, connOpt.get())
|
||||||
|
|
||||||
# Check that it failed gracefully
|
# Check that it failed gracefully
|
||||||
check:
|
check:
|
||||||
@ -225,10 +226,10 @@ suite "Waku Peer Exchange":
|
|||||||
let
|
let
|
||||||
switch = newTestSwitch()
|
switch = newTestSwitch()
|
||||||
peerManager = PeerManager.new(switch)
|
peerManager = PeerManager.new(switch)
|
||||||
peerExchange = WakuPeerExchange.new(peerManager)
|
peerExchangeClient = WakuPeerExchangeClient.new(peerManager)
|
||||||
|
|
||||||
# When requesting 0 peers
|
# When requesting 0 peers
|
||||||
let response = await peerExchange.request(0)
|
let response = await peerExchangeClient.request(0)
|
||||||
|
|
||||||
# Then the response should be an error
|
# Then the response should be an error
|
||||||
check:
|
check:
|
||||||
@ -278,7 +279,7 @@ suite "Waku Peer Exchange":
|
|||||||
|
|
||||||
# Start and mount peer exchange
|
# Start and mount peer exchange
|
||||||
await allFutures([node1.start(), node2.start()])
|
await allFutures([node1.start(), node2.start()])
|
||||||
await allFutures([node1.mountPeerExchange(), node2.mountPeerExchange()])
|
await allFutures([node1.mountPeerExchange(), node2.mountPeerExchangeClient()])
|
||||||
|
|
||||||
# Connect the nodes
|
# Connect the nodes
|
||||||
let dialResponse = await node2.peerManager.dialPeer(
|
let dialResponse = await node2.peerManager.dialPeer(
|
||||||
@ -294,7 +295,7 @@ suite "Waku Peer Exchange":
|
|||||||
node1.wakuPeerExchange.enrCache.add(record)
|
node1.wakuPeerExchange.enrCache.add(record)
|
||||||
|
|
||||||
# When requesting 0 peers
|
# When requesting 0 peers
|
||||||
let response = await node1.wakuPeerExchange.request(0)
|
let response = await node2.wakuPeerExchangeClient.request(0)
|
||||||
|
|
||||||
# Then the response should be empty
|
# Then the response should be empty
|
||||||
assertResultOk(response)
|
assertResultOk(response)
|
||||||
@ -310,19 +311,19 @@ suite "Waku Peer Exchange":
|
|||||||
|
|
||||||
# Start and mount peer exchange
|
# Start and mount peer exchange
|
||||||
await allFutures([node1.start(), node2.start()])
|
await allFutures([node1.start(), node2.start()])
|
||||||
await allFutures([node1.mountPeerExchange(), node2.mountPeerExchange()])
|
await allFutures([node1.mountPeerExchangeClient(), node2.mountPeerExchange()])
|
||||||
|
|
||||||
# Mock that we have discovered one enr
|
# Mock that we have discovered one enr
|
||||||
var record = enr.Record()
|
var record = enr.Record()
|
||||||
check record.fromUri(
|
check record.fromUri(
|
||||||
"enr:-Iu4QGNuTvNRulF3A4Kb9YHiIXLr0z_CpvWkWjWKU-o95zUPR_In02AWek4nsSk7G_-YDcaT4bDRPzt5JIWvFqkXSNcBgmlkgnY0gmlwhE0WsGeJc2VjcDI1NmsxoQKp9VzU2FAh7fwOwSpg1M_Ekz4zzl0Fpbg6po2ZwgVwQYN0Y3CC6mCFd2FrdTIB"
|
"enr:-Iu4QGNuTvNRulF3A4Kb9YHiIXLr0z_CpvWkWjWKU-o95zUPR_In02AWek4nsSk7G_-YDcaT4bDRPzt5JIWvFqkXSNcBgmlkgnY0gmlwhE0WsGeJc2VjcDI1NmsxoQKp9VzU2FAh7fwOwSpg1M_Ekz4zzl0Fpbg6po2ZwgVwQYN0Y3CC6mCFd2FrdTIB"
|
||||||
)
|
)
|
||||||
node1.wakuPeerExchange.enrCache.add(record)
|
node2.wakuPeerExchange.enrCache.add(record)
|
||||||
|
|
||||||
# When making any request with an invalid peer info
|
# When making any request with an invalid peer info
|
||||||
var remotePeerInfo2 = node2.peerInfo.toRemotePeerInfo()
|
var remotePeerInfo2 = node2.peerInfo.toRemotePeerInfo()
|
||||||
remotePeerInfo2.peerId.data.add(255.byte)
|
remotePeerInfo2.peerId.data.add(255.byte)
|
||||||
let response = await node1.wakuPeerExchange.request(1, remotePeerInfo2)
|
let response = await node1.wakuPeerExchangeClient.request(1, remotePeerInfo2)
|
||||||
|
|
||||||
# Then the response should be an error
|
# Then the response should be an error
|
||||||
check:
|
check:
|
||||||
@ -337,10 +338,11 @@ suite "Waku Peer Exchange":
|
|||||||
|
|
||||||
await allFutures(nodes.mapIt(it.start()))
|
await allFutures(nodes.mapIt(it.start()))
|
||||||
await allFutures(nodes.mapIt(it.mountPeerExchange()))
|
await allFutures(nodes.mapIt(it.mountPeerExchange()))
|
||||||
|
await allFutures(nodes.mapIt(it.mountPeerExchangeClient()))
|
||||||
|
|
||||||
# Multiple nodes request to node 0
|
# Multiple nodes request to node 0
|
||||||
for i in 1 ..< 3:
|
for i in 1 ..< 3:
|
||||||
let resp = await nodes[i].wakuPeerExchange.request(
|
let resp = await nodes[i].wakuPeerExchangeClient.request(
|
||||||
2, nodes[0].switch.peerInfo.toRemotePeerInfo()
|
2, nodes[0].switch.peerInfo.toRemotePeerInfo()
|
||||||
)
|
)
|
||||||
require resp.isOk
|
require resp.isOk
|
||||||
@ -409,7 +411,7 @@ suite "Waku Peer Exchange":
|
|||||||
await allFutures(
|
await allFutures(
|
||||||
[
|
[
|
||||||
node1.mountPeerExchange(rateLimit = (1, 150.milliseconds)),
|
node1.mountPeerExchange(rateLimit = (1, 150.milliseconds)),
|
||||||
node2.mountPeerExchange(),
|
node2.mountPeerExchangeClient(),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -436,19 +438,19 @@ suite "Waku Peer Exchange":
|
|||||||
await sleepAsync(150.milliseconds)
|
await sleepAsync(150.milliseconds)
|
||||||
|
|
||||||
# Request 2 peer from px. Test all request variants
|
# Request 2 peer from px. Test all request variants
|
||||||
let response1 = await node2.wakuPeerExchange.request(1)
|
let response1 = await node2.wakuPeerExchangeClient.request(1)
|
||||||
check:
|
check:
|
||||||
response1.isOk
|
response1.isOk
|
||||||
response1.get().peerInfos.len == 1
|
response1.get().peerInfos.len == 1
|
||||||
|
|
||||||
let response2 =
|
let response2 =
|
||||||
await node2.wakuPeerExchange.request(1, node1.peerInfo.toRemotePeerInfo())
|
await node2.wakuPeerExchangeClient.request(1, node1.peerInfo.toRemotePeerInfo())
|
||||||
check:
|
check:
|
||||||
response2.isErr
|
response2.isErr
|
||||||
response2.error().status_code == PeerExchangeResponseStatusCode.TOO_MANY_REQUESTS
|
response2.error().status_code == PeerExchangeResponseStatusCode.TOO_MANY_REQUESTS
|
||||||
|
|
||||||
await sleepAsync(150.milliseconds)
|
await sleepAsync(150.milliseconds)
|
||||||
let response3 = await node2.wakuPeerExchange.request(1, connOpt.get())
|
let response3 = await node2.wakuPeerExchangeClient.request(1, connOpt.get())
|
||||||
check:
|
check:
|
||||||
response3.isOk
|
response3.isOk
|
||||||
response3.get().peerInfos.len == 1
|
response3.get().peerInfos.len == 1
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import
|
|||||||
waku_peer_exchange,
|
waku_peer_exchange,
|
||||||
waku_peer_exchange/rpc,
|
waku_peer_exchange/rpc,
|
||||||
waku_peer_exchange/protocol,
|
waku_peer_exchange/protocol,
|
||||||
|
waku_peer_exchange/client,
|
||||||
node/peer_manager,
|
node/peer_manager,
|
||||||
waku_core,
|
waku_core,
|
||||||
],
|
],
|
||||||
@ -40,7 +41,8 @@ proc dialForPeerExchange*(
|
|||||||
require connOpt.isSome()
|
require connOpt.isSome()
|
||||||
await sleepAsync(FUTURE_TIMEOUT_SHORT)
|
await sleepAsync(FUTURE_TIMEOUT_SHORT)
|
||||||
|
|
||||||
let response = await client.wakuPeerExchange.request(requestedPeers, connOpt.get())
|
let response =
|
||||||
|
await client.wakuPeerExchangeClient.request(requestedPeers, connOpt.get())
|
||||||
assertResultOk(response)
|
assertResultOk(response)
|
||||||
|
|
||||||
if uint64(response.get().peerInfos.len) > minimumPeers:
|
if uint64(response.get().peerInfos.len) > minimumPeers:
|
||||||
|
|||||||
@ -615,8 +615,10 @@ proc build*(
|
|||||||
protectedShards: protectedShards,
|
protectedShards: protectedShards,
|
||||||
relay: relay,
|
relay: relay,
|
||||||
lightPush: lightPush,
|
lightPush: lightPush,
|
||||||
peerExchange: peerExchange,
|
peerExchangeService: peerExchange,
|
||||||
rendezvous: rendezvous,
|
rendezvous: rendezvous,
|
||||||
|
peerExchangeDiscovery: true,
|
||||||
|
# enabling peer exchange client by default for quicker bootstrapping
|
||||||
remoteStoreNode: builder.remoteStoreNode,
|
remoteStoreNode: builder.remoteStoreNode,
|
||||||
remoteLightPushNode: builder.remoteLightPushNode,
|
remoteLightPushNode: builder.remoteLightPushNode,
|
||||||
remoteFilterNode: builder.remoteFilterNode,
|
remoteFilterNode: builder.remoteFilterNode,
|
||||||
|
|||||||
@ -412,7 +412,7 @@ proc setupProtocols(
|
|||||||
return err("failed to set node waku filter peer: " & filterNode.error)
|
return err("failed to set node waku filter peer: " & filterNode.error)
|
||||||
|
|
||||||
# waku peer exchange setup
|
# waku peer exchange setup
|
||||||
if conf.peerExchange:
|
if conf.peerExchangeService:
|
||||||
try:
|
try:
|
||||||
await mountPeerExchange(
|
await mountPeerExchange(
|
||||||
node, some(conf.clusterId), node.rateLimitSettings.getSetting(PEEREXCHG)
|
node, some(conf.clusterId), node.rateLimitSettings.getSetting(PEEREXCHG)
|
||||||
@ -429,6 +429,8 @@ proc setupProtocols(
|
|||||||
return
|
return
|
||||||
err("failed to set node waku peer-exchange peer: " & peerExchangeNode.error)
|
err("failed to set node waku peer-exchange peer: " & peerExchangeNode.error)
|
||||||
|
|
||||||
|
if conf.peerExchangeDiscovery:
|
||||||
|
await node.mountPeerExchangeClient()
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
## Start node
|
## Start node
|
||||||
@ -473,7 +475,7 @@ proc startNode*(
|
|||||||
#
|
#
|
||||||
# Use px to periodically get peers if discv5 is disabled, as discv5 nodes have their own
|
# Use px to periodically get peers if discv5 is disabled, as discv5 nodes have their own
|
||||||
# periodic loop to find peers and px returned peers actually come from discv5
|
# periodic loop to find peers and px returned peers actually come from discv5
|
||||||
if conf.peerExchange and not conf.discv5Conf.isSome():
|
if conf.peerExchangeDiscovery and not conf.discv5Conf.isSome():
|
||||||
node.startPeerExchangeLoop()
|
node.startPeerExchangeLoop()
|
||||||
|
|
||||||
# Maintain relay connections
|
# Maintain relay connections
|
||||||
|
|||||||
@ -85,7 +85,8 @@ type WakuConf* {.requiresInit.} = ref object
|
|||||||
|
|
||||||
relay*: bool
|
relay*: bool
|
||||||
lightPush*: bool
|
lightPush*: bool
|
||||||
peerExchange*: bool
|
peerExchangeService*: bool
|
||||||
|
peerExchangeDiscovery*: bool
|
||||||
|
|
||||||
# TODO: remove relay peer exchange
|
# TODO: remove relay peer exchange
|
||||||
relayPeerExchange*: bool
|
relayPeerExchange*: bool
|
||||||
@ -145,7 +146,7 @@ proc logConf*(conf: WakuConf) =
|
|||||||
store = conf.storeServiceConf.isSome(),
|
store = conf.storeServiceConf.isSome(),
|
||||||
filter = conf.filterServiceConf.isSome(),
|
filter = conf.filterServiceConf.isSome(),
|
||||||
lightPush = conf.lightPush,
|
lightPush = conf.lightPush,
|
||||||
peerExchange = conf.peerExchange
|
peerExchange = conf.peerExchangeService
|
||||||
|
|
||||||
info "Configuration. Network", cluster = conf.clusterId
|
info "Configuration. Network", cluster = conf.clusterId
|
||||||
|
|
||||||
|
|||||||
@ -111,6 +111,7 @@ type
|
|||||||
wakuLightPush*: WakuLightPush
|
wakuLightPush*: WakuLightPush
|
||||||
wakuLightpushClient*: WakuLightPushClient
|
wakuLightpushClient*: WakuLightPushClient
|
||||||
wakuPeerExchange*: WakuPeerExchange
|
wakuPeerExchange*: WakuPeerExchange
|
||||||
|
wakuPeerExchangeClient*: WakuPeerExchangeClient
|
||||||
wakuMetadata*: WakuMetadata
|
wakuMetadata*: WakuMetadata
|
||||||
wakuAutoSharding*: Option[Sharding]
|
wakuAutoSharding*: Option[Sharding]
|
||||||
enr*: enr.Record
|
enr*: enr.Record
|
||||||
@ -1281,21 +1282,26 @@ proc mountPeerExchange*(
|
|||||||
except LPError:
|
except LPError:
|
||||||
error "failed to mount wakuPeerExchange", error = getCurrentExceptionMsg()
|
error "failed to mount wakuPeerExchange", error = getCurrentExceptionMsg()
|
||||||
|
|
||||||
|
proc mountPeerExchangeClient*(node: WakuNode) {.async: (raises: []).} =
|
||||||
|
info "mounting waku peer exchange client"
|
||||||
|
if node.wakuPeerExchangeClient.isNil():
|
||||||
|
node.wakuPeerExchangeClient = WakuPeerExchangeClient.new(node.peerManager)
|
||||||
|
|
||||||
proc fetchPeerExchangePeers*(
|
proc fetchPeerExchangePeers*(
|
||||||
node: Wakunode, amount = DefaultPXNumPeersReq
|
node: Wakunode, amount = DefaultPXNumPeersReq
|
||||||
): Future[Result[int, PeerExchangeResponseStatus]] {.async: (raises: []).} =
|
): Future[Result[int, PeerExchangeResponseStatus]] {.async: (raises: []).} =
|
||||||
if node.wakuPeerExchange.isNil():
|
if node.wakuPeerExchangeClient.isNil():
|
||||||
error "could not get peers from px, waku peer-exchange is nil"
|
error "could not get peers from px, waku peer-exchange-client is nil"
|
||||||
return err(
|
return err(
|
||||||
(
|
(
|
||||||
status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE,
|
status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE,
|
||||||
status_desc: some("PeerExchange is not mounted"),
|
status_desc: some("PeerExchangeClient is not mounted"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
info "Retrieving peer info via peer exchange protocol", amount
|
info "Retrieving peer info via peer exchange protocol", amount
|
||||||
let pxPeersRes = await node.wakuPeerExchange.request(amount)
|
let pxPeersRes = await node.wakuPeerExchangeClient.request(amount)
|
||||||
if pxPeersRes.isOk:
|
if pxPeersRes.isOk():
|
||||||
var validPeers = 0
|
var validPeers = 0
|
||||||
let peers = pxPeersRes.get().peerInfos
|
let peers = pxPeersRes.get().peerInfos
|
||||||
for pi in peers:
|
for pi in peers:
|
||||||
@ -1313,17 +1319,19 @@ proc fetchPeerExchangePeers*(
|
|||||||
|
|
||||||
proc peerExchangeLoop(node: WakuNode) {.async.} =
|
proc peerExchangeLoop(node: WakuNode) {.async.} =
|
||||||
while true:
|
while true:
|
||||||
await sleepAsync(1.minutes)
|
|
||||||
if not node.started:
|
if not node.started:
|
||||||
|
await sleepAsync(5.seconds)
|
||||||
continue
|
continue
|
||||||
(await node.fetchPeerExchangePeers()).isOkOr:
|
(await node.fetchPeerExchangePeers()).isOkOr:
|
||||||
warn "Cannot fetch peers from peer exchange", cause = error
|
warn "Cannot fetch peers from peer exchange", cause = error
|
||||||
|
await sleepAsync(1.minutes)
|
||||||
|
|
||||||
proc startPeerExchangeLoop*(node: WakuNode) =
|
proc startPeerExchangeLoop*(node: WakuNode) =
|
||||||
if node.wakuPeerExchange.isNil():
|
if node.wakuPeerExchangeClient.isNil():
|
||||||
error "startPeerExchangeLoop: Peer Exchange is not mounted"
|
error "startPeerExchangeLoop: Peer Exchange is not mounted"
|
||||||
return
|
return
|
||||||
node.wakuPeerExchange.pxLoopHandle = node.peerExchangeLoop()
|
info "Starting peer exchange loop"
|
||||||
|
node.wakuPeerExchangeClient.pxLoopHandle = node.peerExchangeLoop()
|
||||||
|
|
||||||
# TODO: Move to application module (e.g., wakunode2.nim)
|
# TODO: Move to application module (e.g., wakunode2.nim)
|
||||||
proc setPeerExchangePeer*(
|
proc setPeerExchangePeer*(
|
||||||
@ -1561,6 +1569,10 @@ proc stop*(node: WakuNode) {.async.} =
|
|||||||
if not node.wakuPeerExchange.isNil() and not node.wakuPeerExchange.pxLoopHandle.isNil():
|
if not node.wakuPeerExchange.isNil() and not node.wakuPeerExchange.pxLoopHandle.isNil():
|
||||||
await node.wakuPeerExchange.pxLoopHandle.cancelAndWait()
|
await node.wakuPeerExchange.pxLoopHandle.cancelAndWait()
|
||||||
|
|
||||||
|
if not node.wakuPeerExchangeClient.isNil() and
|
||||||
|
not node.wakuPeerExchangeClient.pxLoopHandle.isNil():
|
||||||
|
await node.wakuPeerExchangeClient.pxLoopHandle.cancelAndWait()
|
||||||
|
|
||||||
if not node.wakuRendezvous.isNil():
|
if not node.wakuRendezvous.isNil():
|
||||||
await node.wakuRendezvous.stopWait()
|
await node.wakuRendezvous.stopWait()
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import ./waku_peer_exchange/[protocol, rpc]
|
import ./waku_peer_exchange/[protocol, rpc, common, client]
|
||||||
|
|
||||||
export protocol, rpc
|
export protocol, rpc, common, client
|
||||||
|
|||||||
102
waku/waku_peer_exchange/client.nim
Normal file
102
waku/waku_peer_exchange/client.nim
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import std/options, results, chronicles, chronos, metrics
|
||||||
|
|
||||||
|
import ./common, ./rpc, ./rpc_codec, ../node/peer_manager
|
||||||
|
|
||||||
|
from ../waku_core/codecs import WakuPeerExchangeCodec
|
||||||
|
|
||||||
|
declarePublicGauge waku_px_peers_received_total,
|
||||||
|
"number of ENRs received via peer exchange"
|
||||||
|
declarePublicCounter waku_px_client_errors, "number of peer exchange errors", ["type"]
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "waku peer_exchange client"
|
||||||
|
|
||||||
|
type WakuPeerExchangeClient* = ref object
|
||||||
|
peerManager*: PeerManager
|
||||||
|
pxLoopHandle*: Future[void]
|
||||||
|
|
||||||
|
proc new*(T: type WakuPeerExchangeClient, peerManager: PeerManager): T =
|
||||||
|
WakuPeerExchangeClient(peerManager: peerManager)
|
||||||
|
|
||||||
|
proc request*(
|
||||||
|
wpx: WakuPeerExchangeClient, numPeers = DefaultPXNumPeersReq, conn: Connection
|
||||||
|
): Future[WakuPeerExchangeResult[PeerExchangeResponse]] {.async: (raises: []).} =
|
||||||
|
let rpc = PeerExchangeRpc.makeRequest(numPeers)
|
||||||
|
|
||||||
|
var buffer: seq[byte]
|
||||||
|
var callResult =
|
||||||
|
(status_code: PeerExchangeResponseStatusCode.SUCCESS, status_desc: none(string))
|
||||||
|
try:
|
||||||
|
await conn.writeLP(rpc.encode().buffer)
|
||||||
|
buffer = await conn.readLp(DefaultMaxRpcSize.int)
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "exception when handling peer exchange request", error = exc.msg
|
||||||
|
waku_px_client_errors.inc(labelValues = ["error_sending_or_receiving_px_req"])
|
||||||
|
callResult = (
|
||||||
|
status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE,
|
||||||
|
status_desc: some($exc.msg),
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
# close, no more data is expected
|
||||||
|
await conn.closeWithEof()
|
||||||
|
|
||||||
|
if callResult.status_code != PeerExchangeResponseStatusCode.SUCCESS:
|
||||||
|
error "peer exchange request failed", status_code = callResult.status_code
|
||||||
|
return err(callResult)
|
||||||
|
|
||||||
|
let decoded = PeerExchangeRpc.decode(buffer).valueOr:
|
||||||
|
error "peer exchange request error decoding buffer", error = $error
|
||||||
|
return err(
|
||||||
|
(
|
||||||
|
status_code: PeerExchangeResponseStatusCode.BAD_RESPONSE,
|
||||||
|
status_desc: some($error),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if decoded.response.status_code != PeerExchangeResponseStatusCode.SUCCESS:
|
||||||
|
error "peer exchange request error", status_code = decoded.response.status_code
|
||||||
|
return err(
|
||||||
|
(
|
||||||
|
status_code: decoded.response.status_code,
|
||||||
|
status_desc: decoded.response.status_desc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return ok(decoded.response)
|
||||||
|
|
||||||
|
proc request*(
|
||||||
|
wpx: WakuPeerExchangeClient, numPeers = DefaultPXNumPeersReq, peer: RemotePeerInfo
|
||||||
|
): Future[WakuPeerExchangeResult[PeerExchangeResponse]] {.async: (raises: []).} =
|
||||||
|
try:
|
||||||
|
let connOpt = await wpx.peerManager.dialPeer(peer, WakuPeerExchangeCodec)
|
||||||
|
if connOpt.isNone():
|
||||||
|
error "error in request connOpt is none"
|
||||||
|
return err(
|
||||||
|
(
|
||||||
|
status_code: PeerExchangeResponseStatusCode.DIAL_FAILURE,
|
||||||
|
status_desc: some(dialFailure),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return await wpx.request(numPeers, connOpt.get())
|
||||||
|
except CatchableError:
|
||||||
|
error "peer exchange request exception", error = getCurrentExceptionMsg()
|
||||||
|
return err(
|
||||||
|
(
|
||||||
|
status_code: PeerExchangeResponseStatusCode.BAD_RESPONSE,
|
||||||
|
status_desc: some("exception dialing peer: " & getCurrentExceptionMsg()),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
proc request*(
|
||||||
|
wpx: WakuPeerExchangeClient, numPeers = DefaultPXNumPeersReq
|
||||||
|
): Future[WakuPeerExchangeResult[PeerExchangeResponse]] {.async: (raises: []).} =
|
||||||
|
let peerOpt = wpx.peerManager.selectPeer(WakuPeerExchangeCodec)
|
||||||
|
if peerOpt.isNone():
|
||||||
|
waku_px_client_errors.inc(labelValues = [peerNotFoundFailure])
|
||||||
|
error "peer exchange error peerOpt is none"
|
||||||
|
return err(
|
||||||
|
(
|
||||||
|
status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE,
|
||||||
|
status_desc: some(peerNotFoundFailure),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return await wpx.request(numPeers, peerOpt.get())
|
||||||
21
waku/waku_peer_exchange/common.nim
Normal file
21
waku/waku_peer_exchange/common.nim
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import results, metrics, chronos
|
||||||
|
import ./rpc, ../waku_core
|
||||||
|
|
||||||
|
const
|
||||||
|
# We add a 64kB safety buffer for protocol overhead.
|
||||||
|
# 10x-multiplier also for safety
|
||||||
|
DefaultMaxRpcSize* = 10 * DefaultMaxWakuMessageSize + 64 * 1024
|
||||||
|
# TODO what is the expected size of a PX message? As currently specified, it can contain an arbitrary number of ENRs...
|
||||||
|
MaxPeersCacheSize* = 60
|
||||||
|
CacheRefreshInterval* = 10.minutes
|
||||||
|
DefaultPXNumPeersReq* = 5.uint64()
|
||||||
|
|
||||||
|
# Error types (metric label values)
|
||||||
|
const
|
||||||
|
dialFailure* = "dial_failure"
|
||||||
|
peerNotFoundFailure* = "peer_not_found_failure"
|
||||||
|
decodeRpcFailure* = "decode_rpc_failure"
|
||||||
|
retrievePeersDiscv5Error* = "retrieve_peers_discv5_failure"
|
||||||
|
pxFailure* = "px_failure"
|
||||||
|
|
||||||
|
type WakuPeerExchangeResult*[T] = Result[T, PeerExchangeResponseStatus]
|
||||||
@ -14,136 +14,29 @@ import
|
|||||||
../discovery/waku_discv5,
|
../discovery/waku_discv5,
|
||||||
./rpc,
|
./rpc,
|
||||||
./rpc_codec,
|
./rpc_codec,
|
||||||
../common/rate_limit/request_limiter
|
../common/rate_limit/request_limiter,
|
||||||
|
./common
|
||||||
|
|
||||||
from ../waku_core/codecs import WakuPeerExchangeCodec
|
from ../waku_core/codecs import WakuPeerExchangeCodec
|
||||||
export WakuPeerExchangeCodec
|
export WakuPeerExchangeCodec
|
||||||
|
|
||||||
declarePublicGauge waku_px_peers_received_total,
|
|
||||||
"number of ENRs received via peer exchange"
|
|
||||||
declarePublicGauge waku_px_peers_received_unknown,
|
declarePublicGauge waku_px_peers_received_unknown,
|
||||||
"number of previously unknown ENRs received via peer exchange"
|
"number of previously unknown ENRs received via peer exchange"
|
||||||
declarePublicCounter waku_px_peers_sent,
|
|
||||||
"number of ENRs sent to peer exchange requesters"
|
|
||||||
declarePublicGauge waku_px_peers_cached, "number of peer exchange peer ENRs cached"
|
declarePublicGauge waku_px_peers_cached, "number of peer exchange peer ENRs cached"
|
||||||
declarePublicCounter waku_px_errors, "number of peer exchange errors", ["type"]
|
declarePublicCounter waku_px_errors, "number of peer exchange errors", ["type"]
|
||||||
|
declarePublicCounter waku_px_peers_sent,
|
||||||
|
"number of ENRs sent to peer exchange requesters"
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "waku peer_exchange"
|
topics = "waku peer_exchange"
|
||||||
|
|
||||||
const
|
type WakuPeerExchange* = ref object of LPProtocol
|
||||||
# We add a 64kB safety buffer for protocol overhead.
|
peerManager*: PeerManager
|
||||||
# 10x-multiplier also for safety
|
enrCache*: seq[enr.Record]
|
||||||
DefaultMaxRpcSize* = 10 * DefaultMaxWakuMessageSize + 64 * 1024
|
cluster*: Option[uint16]
|
||||||
# TODO what is the expected size of a PX message? As currently specified, it can contain an arbitary number of ENRs...
|
# todo: next step: ring buffer; future: implement cache satisfying https://rfc.vac.dev/spec/34/
|
||||||
MaxPeersCacheSize = 60
|
requestRateLimiter*: RequestRateLimiter
|
||||||
CacheRefreshInterval = 10.minutes
|
pxLoopHandle*: Future[void]
|
||||||
DefaultPXNumPeersReq* = 5.uint64()
|
|
||||||
|
|
||||||
# Error types (metric label values)
|
|
||||||
const
|
|
||||||
dialFailure = "dial_failure"
|
|
||||||
peerNotFoundFailure = "peer_not_found_failure"
|
|
||||||
decodeRpcFailure = "decode_rpc_failure"
|
|
||||||
retrievePeersDiscv5Error = "retrieve_peers_discv5_failure"
|
|
||||||
pxFailure = "px_failure"
|
|
||||||
|
|
||||||
type
|
|
||||||
WakuPeerExchangeResult*[T] = Result[T, PeerExchangeResponseStatus]
|
|
||||||
|
|
||||||
WakuPeerExchange* = ref object of LPProtocol
|
|
||||||
peerManager*: PeerManager
|
|
||||||
enrCache*: seq[enr.Record]
|
|
||||||
cluster*: Option[uint16]
|
|
||||||
# todo: next step: ring buffer; future: implement cache satisfying https://rfc.vac.dev/spec/34/
|
|
||||||
requestRateLimiter*: RequestRateLimiter
|
|
||||||
pxLoopHandle*: Future[void]
|
|
||||||
|
|
||||||
proc request*(
|
|
||||||
wpx: WakuPeerExchange, numPeers = DefaultPXNumPeersReq, conn: Connection
|
|
||||||
): Future[WakuPeerExchangeResult[PeerExchangeResponse]] {.async: (raises: []).} =
|
|
||||||
let rpc = PeerExchangeRpc.makeRequest(numPeers)
|
|
||||||
|
|
||||||
var buffer: seq[byte]
|
|
||||||
var callResult =
|
|
||||||
(status_code: PeerExchangeResponseStatusCode.SUCCESS, status_desc: none(string))
|
|
||||||
try:
|
|
||||||
await conn.writeLP(rpc.encode().buffer)
|
|
||||||
buffer = await conn.readLp(DefaultMaxRpcSize.int)
|
|
||||||
except CatchableError as exc:
|
|
||||||
error "exception when handling peer exchange request",
|
|
||||||
error = getCurrentExceptionMsg()
|
|
||||||
waku_px_errors.inc(labelValues = [exc.msg])
|
|
||||||
callResult = (
|
|
||||||
status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE,
|
|
||||||
status_desc: some($exc.msg),
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
# close, no more data is expected
|
|
||||||
await conn.closeWithEof()
|
|
||||||
|
|
||||||
if callResult.status_code != PeerExchangeResponseStatusCode.SUCCESS:
|
|
||||||
error "peer exchange request failed", status_code = callResult.status_code
|
|
||||||
return err(callResult)
|
|
||||||
|
|
||||||
let decodedBuff = PeerExchangeRpc.decode(buffer)
|
|
||||||
if decodedBuff.isErr():
|
|
||||||
error "peer exchange request error decoding buffer", error = $decodedBuff.error
|
|
||||||
return err(
|
|
||||||
(
|
|
||||||
status_code: PeerExchangeResponseStatusCode.BAD_RESPONSE,
|
|
||||||
status_desc: some($decodedBuff.error),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if decodedBuff.get().response.status_code != PeerExchangeResponseStatusCode.SUCCESS:
|
|
||||||
error "peer exchange request error",
|
|
||||||
status_code = decodedBuff.get().response.status_code
|
|
||||||
return err(
|
|
||||||
(
|
|
||||||
status_code: decodedBuff.get().response.status_code,
|
|
||||||
status_desc: decodedBuff.get().response.status_desc,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return ok(decodedBuff.get().response)
|
|
||||||
|
|
||||||
proc request*(
|
|
||||||
wpx: WakuPeerExchange, numPeers = DefaultPXNumPeersReq, peer: RemotePeerInfo
|
|
||||||
): Future[WakuPeerExchangeResult[PeerExchangeResponse]] {.async: (raises: []).} =
|
|
||||||
try:
|
|
||||||
let connOpt = await wpx.peerManager.dialPeer(peer, WakuPeerExchangeCodec)
|
|
||||||
if connOpt.isNone():
|
|
||||||
error "error in request connOpt is none"
|
|
||||||
return err(
|
|
||||||
(
|
|
||||||
status_code: PeerExchangeResponseStatusCode.DIAL_FAILURE,
|
|
||||||
status_desc: some(dialFailure),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return await wpx.request(numPeers, connOpt.get())
|
|
||||||
except CatchableError:
|
|
||||||
error "peer exchange request exception", error = getCurrentExceptionMsg()
|
|
||||||
return err(
|
|
||||||
(
|
|
||||||
status_code: PeerExchangeResponseStatusCode.BAD_RESPONSE,
|
|
||||||
status_desc: some("exception dialing peer: " & getCurrentExceptionMsg()),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
proc request*(
|
|
||||||
wpx: WakuPeerExchange, numPeers = DefaultPXNumPeersReq
|
|
||||||
): Future[WakuPeerExchangeResult[PeerExchangeResponse]] {.async: (raises: []).} =
|
|
||||||
let peerOpt = wpx.peerManager.selectPeer(WakuPeerExchangeCodec)
|
|
||||||
if peerOpt.isNone():
|
|
||||||
waku_px_errors.inc(labelValues = [peerNotFoundFailure])
|
|
||||||
error "peer exchange error peerOpt is none"
|
|
||||||
return err(
|
|
||||||
(
|
|
||||||
status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE,
|
|
||||||
status_desc: some(peerNotFoundFailure),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return await wpx.request(numPeers, peerOpt.get())
|
|
||||||
|
|
||||||
proc respond(
|
proc respond(
|
||||||
wpx: WakuPeerExchange, enrs: seq[enr.Record], conn: Connection
|
wpx: WakuPeerExchange, enrs: seq[enr.Record], conn: Connection
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user