From 2b7d6236f383c8eadbdf2e1615b5368eb6bcc4c9 Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 20 Sep 2023 13:31:02 +0200 Subject: [PATCH] Improve rdv advertise --- libp2p/discovery/rendezvousinterface.nim | 11 +++- libp2p/protocols/rendezvous.nim | 4 +- tests/testrendezvous.nim | 11 ++++ tests/testrendezvousinterface.nim | 72 ++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 tests/testrendezvousinterface.nim diff --git a/libp2p/discovery/rendezvousinterface.nim b/libp2p/discovery/rendezvousinterface.nim index b95410b939..e857466cd2 100644 --- a/libp2p/discovery/rendezvousinterface.nim +++ b/libp2p/discovery/rendezvousinterface.nim @@ -19,6 +19,7 @@ type rdv*: RendezVous timeToRequest: Duration timeToAdvertise: Duration + ttl: Duration RdvNamespace* = distinct string @@ -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 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) diff --git a/libp2p/protocols/rendezvous.nim b/libp2p/protocols/rendezvous.nim index 6823d24591..dab7b70c3a 100644 --- a/libp2p/protocols/rendezvous.nim +++ b/libp2p/protocols/rendezvous.nim @@ -476,9 +476,9 @@ proc advertisePeer(rdv: RendezVous, 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: diff --git a/tests/testrendezvous.nim b/tests/testrendezvous.nim index 14adc00cf8..ff7bddf0c5 100644 --- a/tests/testrendezvous.nim +++ b/tests/testrendezvous.nim @@ -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 = @@ -26,6 +27,16 @@ proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch = .withRendezVous(rdv) .build() +type + MockRendezVous = ref object of RendezVous + numAdvertise: int + +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, if needed + # await inherited(self, namespace, ttl) + suite "RendezVous": teardown: checkTrackers() diff --git a/tests/testrendezvousinterface.nim b/tests/testrendezvousinterface.nim new file mode 100644 index 0000000000..4fef880249 --- /dev/null +++ b/tests/testrendezvousinterface.nim @@ -0,0 +1,72 @@ +{.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() + + # Assert that advertisements happened 5 times in 500ms second + 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()))