Skip to content

Commit

Permalink
Improve rdv advertise
Browse files Browse the repository at this point in the history
  • Loading branch information
diegomrsantos committed Sep 21, 2023
1 parent b2eac7e commit a098e22
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 6 deletions.
6 changes: 5 additions & 1 deletion libp2p/discovery/discoverymngr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ proc `{}`*[T](pa: PeerAttributes, t: typedesc[T]): Opt[T] =
proc `[]`*[T](pa: PeerAttributes, t: typedesc[T]): T {.raises: [KeyError].} =
pa{T}.valueOr: raise newException(KeyError, "Attritute not found")

proc add*(pa: var PeerAttributes, other: PeerAttributes) =
for f in other.attributes:
pa.attributes.add(f)

Check warning on line 65 in libp2p/discovery/discoverymngr.nim

View check run for this annotation

Codecov / codecov/patch

libp2p/discovery/discoverymngr.nim#L65

Added line #L65 was not covered by tests

proc match*(pa, candidate: PeerAttributes): bool =
for f in pa.attributes:
block oneAttribute:
Expand Down Expand Up @@ -124,7 +128,7 @@ proc request*[T](dm: DiscoveryManager, value: T): DiscoveryQuery =

proc advertise*(dm: DiscoveryManager, pa: PeerAttributes) =
for i in dm.interfaces:
i.toAdvertise = pa
i.toAdvertise.add(pa)
if i.advertiseLoop.isNil:
i.advertisementUpdated = newAsyncEvent()
i.advertiseLoop = i.advertise()
Expand Down
11 changes: 8 additions & 3 deletions libp2p/discovery/rendezvousinterface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type
rdv*: RendezVous
timeToRequest: Duration
timeToAdvertise: Duration
ttl: Duration

RdvNamespace* = distinct string

Expand Down Expand Up @@ -62,12 +63,16 @@ method advertise*(self: RendezVousInterface) {.async.} =

self.advertisementUpdated.clear()
for toAdv in toAdvertise:
await self.rdv.advertise(toAdv, self.timeToAdvertise)
try:
await self.rdv.advertise(toAdv, self.ttl)
except CatchableError as error:
debug "RendezVous advertise error: ", msg = error.msg

Check warning on line 69 in libp2p/discovery/rendezvousinterface.nim

View check run for this annotation

Codecov / codecov/patch

libp2p/discovery/rendezvousinterface.nim#L69

Added line #L69 was not covered by tests

await sleepAsync(self.timeToAdvertise) or self.advertisementUpdated.wait()

proc new*(T: typedesc[RendezVousInterface],
rdv: RendezVous,
ttr: Duration = 1.minutes,
tta: Duration = MinimumDuration): RendezVousInterface =
T(rdv: rdv, timeToRequest: ttr, timeToAdvertise: tta)
tta: Duration = 1.minutes,
ttl: Duration = MinimumDuration): RendezVousInterface =
T(rdv: rdv, timeToRequest: ttr, timeToAdvertise: tta, ttl: ttl)
6 changes: 4 additions & 2 deletions libp2p/protocols/rendezvous.nim
Original file line number Diff line number Diff line change
Expand Up @@ -469,16 +469,18 @@ proc advertisePeer(rdv: RendezVous,
trace "Unexpected register response", peer, msgType = msgRecv.msgType
elif msgRecv.registerResponse.tryGet().status != ResponseStatus.Ok:
trace "Refuse to register", peer, response = msgRecv.registerResponse
else:
trace "Successfully registered", peer, response = msgRecv.registerResponse
except CatchableError as exc:
trace "exception in the advertise", error = exc.msg
finally:
rdv.sema.release()
await rdv.sema.acquire()
discard await advertiseWrap().withTimeout(5.seconds)

proc advertise*(rdv: RendezVous,
method advertise*(rdv: RendezVous,
ns: string,
ttl: Duration = MinimumDuration) {.async.} =
ttl: Duration = MinimumDuration) {.async, base.} =
let sprBuff = rdv.switch.peerInfo.signedPeerRecord.encode().valueOr:
raise newException(RendezVousError, "Wrong Signed Peer Record")
if ns.len notin 1..255:
Expand Down
1 change: 1 addition & 0 deletions tests/testrendezvous.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import chronos
import ../libp2p/[protocols/rendezvous,
switch,
builders,]
import ../libp2p/discovery/[rendezvousinterface, discoverymngr]
import ./helpers

proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch =
Expand Down
71 changes: 71 additions & 0 deletions tests/testrendezvousinterface.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{.used.}

# Nim-Libp2p
# Copyright (c) 2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.

import sequtils, strutils
import chronos
import ../libp2p/[protocols/rendezvous,
switch,
builders,]
import ../libp2p/discovery/[rendezvousinterface, discoverymngr]
import ./helpers

proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch =
SwitchBuilder.new()
.withRng(newRng())
.withAddresses(@[ MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ])
.withTcpTransport()
.withMplex()
.withNoise()
.withRendezVous(rdv)
.build()

type
MockRendezVous = ref object of RendezVous
numAdvertise: int

MockErrorRendezVous = ref object of MockRendezVous

method advertise*(self: MockRendezVous, namespace: string, ttl: Duration) {.async.} =
# Every time an advertisement is made, increment the counter
self.numAdvertise += 1
# Forward the call to the actual implementation
await procCall RendezVous(self).advertise(namespace, ttl)

method advertise*(self: MockErrorRendezVous, namespace: string, ttl: Duration) {.async.} =
await procCall MockRendezVous(self).advertise(namespace, ttl)
raise newException(CatchableError, "MockErrorRendezVous.advertise")

suite "RendezVous Interface":
teardown:
checkTrackers()

proc baseTimeToAdvertiseTest(rdv: MockRendezVous) {.async.} =
let
tta = 100.milliseconds
ttl = 2.hours
client = createSwitch(rdv)
dm = DiscoveryManager()

await client.start()
dm.add(RendezVousInterface.new(rdv = rdv, tta = tta, ttl = ttl))
dm.advertise(RdvNamespace("ns"))

# Run for 500ms, which with a 100ms advertise interval, should lead to 5 advertisements
await sleepAsync(500.milliseconds)
await client.stop()

check rdv.numAdvertise == 5

asyncTest "Check timeToAdvertise interval":
await baseTimeToAdvertiseTest(MockRendezVous.new(newRng()))

asyncTest "Check timeToAdvertise interval when there is an error":
await baseTimeToAdvertiseTest(MockErrorRendezVous.new(newRng()))

0 comments on commit a098e22

Please sign in to comment.