diff --git a/tests/storage/testnat.nim b/tests/storage/testnat.nim index 7d0e7275..a64fa0f3 100644 --- a/tests/storage/testnat.nim +++ b/tests/storage/testnat.nim @@ -2,6 +2,9 @@ import std/[net] import pkg/chronos import pkg/libp2p/[multiaddress, multihash, multicodec] import pkg/libp2p/protocols/connectivity/autonat/types +import pkg/libp2p/protocols/connectivity/autonatv2/service except setup +import pkg/libp2p/protocols/connectivity/autonatv2/client except setup +import pkg/libp2p/protocols/connectivity/autonatv2/types as autonatv2Types import pkg/libp2p/protocols/connectivity/relay/client as relayClientModule import pkg/libp2p/protocols/connectivity/dcutr/core as dcutrCore import pkg/libp2p/multistream @@ -26,6 +29,17 @@ method mapNatPorts*( .} = m.mappedPorts +type MockAutonatV2Client = ref object of AutonatV2Client + reqAddrs: seq[MultiAddress] + +method sendDialRequest*( + self: MockAutonatV2Client, pid: PeerId, testAddrs: seq[MultiAddress] +): Future[AutonatV2Response] {. + async: (raises: [AutonatV2Error, CancelledError, DialFailedError, LPStreamError]) +.} = + self.reqAddrs = testAddrs + AutonatV2Response(reachability: Unknown) + asyncchecksuite "NAT - handleNatStatus": var sw: Switch var key: PrivateKey @@ -67,6 +81,7 @@ asyncchecksuite "NAT - handleNatStatus": test "handleNatStatus starts autoRelay when NotReachable and no dialBackAddr": let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol))) + autorelayservice.setup(autoRelay, sw) await mapper.handleNatStatus( NotReachable, Opt.none(MultiAddress), discoveryPort, disc, sw, autoRelay ) @@ -78,6 +93,7 @@ asyncchecksuite "NAT - handleNatStatus": let dialBack = MultiAddress.init("/ip4/1.2.3.4/tcp/8080").expect("valid") let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol))) + autorelayservice.setup(autoRelay, sw) await mapper.handleNatStatus( NotReachable, Opt.some(dialBack), discoveryPort, disc, sw, autoRelay ) @@ -86,33 +102,83 @@ asyncchecksuite "NAT - handleNatStatus": check disc.announceAddrs == newSeq[MultiAddress]() check disc.protocol.clientMode - test "handleNatStatus does nothing when Reachable and no dialBackAddr": + test "handleNatStatus stops relay and exits client mode when Reachable": let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol))) - autorelayservice.setup(autoRelay, sw) disc.protocol.clientMode = true + autorelayservice.setup(autoRelay, sw) await mapper.handleNatStatus( Reachable, Opt.none(MultiAddress), discoveryPort, disc, sw, autoRelay ) - check autoRelay.isRunning - check disc.announceAddrs == newSeq[MultiAddress]() - check disc.protocol.clientMode - - test "handleNatStatus stops relay and announces dialBackAddr when Reachable": - let dialBack = MultiAddress.init("/ip4/1.2.3.4/tcp/8080").expect("valid") - let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol))) - - disc.protocol.clientMode = true - autorelayservice.setup(autoRelay, sw) - await mapper.handleNatStatus( - Reachable, Opt.some(dialBack), discoveryPort, disc, sw, autoRelay - ) - check not autoRelay.isRunning - check disc.announceAddrs == @[dialBack] check not disc.protocol.clientMode + test "announcePeerInfoAddrs excludes relay circuit addresses": + let circuitAddr = MultiAddress + .init("/ip4/1.2.3.4/tcp/4040/p2p/" & $sw.peerInfo.peerId & "/p2p-circuit") + .expect("valid") + sw.peerInfo.addrs.add(circuitAddr) + + announcePeerInfoAddrs(disc, sw.peerInfo, discoveryPort) + + check circuitAddr notin disc.announceAddrs + check disc.announceAddrs == sw.peerInfo.addrs.filterIt(it != circuitAddr) + + test "announcePeerInfoAddrs does nothing when addresses are already announced": + announcePeerInfoAddrs(disc, sw.peerInfo, discoveryPort) + let seqNo = disc.getSpr().data.seqNo + + announcePeerInfoAddrs(disc, sw.peerInfo, discoveryPort) + + check disc.getSpr().data.seqNo == seqNo + + test "peerInfo observer announces addresses when Reachable": + let autonat = AutonatV2Service.new(Rng.instance()) + discard setupPeerInfoObserver(sw, autonat, disc, discoveryPort) + autonat.networkReachability = Reachable + + sw.peerInfo.listenAddrs.add( + MultiAddress.init("/ip4/1.2.3.4/tcp/9999").expect("valid") + ) + await sw.peerInfo.update() + + check disc.announceAddrs == sw.peerInfo.addrs + + test "peerInfo observer does not announce when the node is not Reachable": + let autonat = AutonatV2Service.new(Rng.instance()) + discard setupPeerInfoObserver(sw, autonat, disc, discoveryPort) + autonat.networkReachability = NotReachable + + sw.peerInfo.listenAddrs.add( + MultiAddress.init("/ip4/1.2.3.4/tcp/9999").expect("valid") + ) + await sw.peerInfo.update() + + check disc.announceAddrs == newSeq[MultiAddress]() + + test "autonat dial request includes the observed addresses as candidates": + # Reproduces vacp2p/nim-libp2p#2600: until that fix is vendored, the + # dial request only contains peerInfo.addrs (private listen addrs), so + # a NATed node never submits a dialable candidate. + let client = MockAutonatV2Client() + let autonat = AutonatV2Service.new(Rng.instance(), client) + service.setup(autonat, sw) + await autonat.start(sw) + + let observed = MultiAddress.init("/ip4/8.8.8.8/tcp/4001").expect("valid") + for _ in 0 ..< 3: # minCount: 3 observations before the manager trusts an addr + discard sw.peerStore.identify.observedAddrManager.addObservation(observed) + + let sw2 = newStandardSwitch() + await sw2.start() + await sw.connect(sw2.peerInfo.peerId, sw2.peerInfo.addrs) + + check eventually(observed in client.reqAddrs) + + await autonat.stop(sw) + await sw2.stop() + asyncchecksuite "NAT - Hole punching": test "setupHolePunching mounts the dcutr protocol on the switch": let sw = newStandardSwitch() diff --git a/vendor/nim-libp2p b/vendor/nim-libp2p index c4319937..2be4e5ed 160000 --- a/vendor/nim-libp2p +++ b/vendor/nim-libp2p @@ -1 +1 @@ -Subproject commit c43199378f46d0aaf61be1cad1ee1d63e8f665d6 +Subproject commit 2be4e5edb39c113be7c293d53ec17c6cadbb9640