nim-libp2p/tests/testidentify.nim

250 lines
9.2 KiB
Nim

import options
import chronos, strutils, sequtils, sets, algorithm
import ../libp2p/[protocols/identify,
multiaddress,
peerinfo,
peerid,
stream/connection,
multistream,
transports/transport,
switch,
builders,
transports/tcptransport,
crypto/crypto,
upgrademngrs/upgrade]
import ./helpers
when defined(nimHasUsed): {.used.}
suite "Identify":
teardown:
checkTrackers()
suite "handle identify message":
var
ma {.threadvar.}: seq[MultiAddress]
remoteSecKey {.threadvar.}: PrivateKey
remotePeerInfo {.threadvar.}: PeerInfo
serverFut {.threadvar.}: Future[void]
acceptFut {.threadvar.}: Future[void]
identifyProto1 {.threadvar.}: Identify
identifyProto2 {.threadvar.}: Identify
transport1 {.threadvar.}: Transport
transport2 {.threadvar.}: Transport
msListen {.threadvar.}: MultistreamSelect
msDial {.threadvar.}: MultistreamSelect
conn {.threadvar.}: Connection
asyncSetup:
ma = @[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()]
remoteSecKey = PrivateKey.random(ECDSA, rng[]).get()
remotePeerInfo = PeerInfo.new(
remoteSecKey,
ma,
["/test/proto1/1.0.0", "/test/proto2/1.0.0"])
transport1 = TcpTransport.new(upgrade = Upgrade())
transport2 = TcpTransport.new(upgrade = Upgrade())
identifyProto1 = Identify.new(remotePeerInfo)
identifyProto2 = Identify.new(remotePeerInfo)
msListen = MultistreamSelect.new()
msDial = MultistreamSelect.new()
serverFut = transport1.start(ma)
await remotePeerInfo.update()
asyncTeardown:
await conn.close()
await acceptFut
await transport1.stop()
await serverFut
await transport2.stop()
asyncTest "default agent version":
msListen.addHandler(IdentifyCodec, identifyProto1)
proc acceptHandler(): Future[void] {.async, gcsafe.} =
let c = await transport1.accept()
await msListen.handle(c)
acceptFut = acceptHandler()
conn = await transport2.dial(transport1.addrs[0])
discard await msDial.select(conn, IdentifyCodec)
let id = await identifyProto2.identify(conn, remotePeerInfo.peerId)
check id.pubkey.get() == remoteSecKey.getPublicKey().get()
check id.addrs == ma
check id.protoVersion.get() == ProtoVersion
check id.agentVersion.get() == AgentVersion
check id.protos == @["/test/proto1/1.0.0", "/test/proto2/1.0.0"]
check id.signedPeerRecord.isNone()
asyncTest "custom agent version":
const customAgentVersion = "MY CUSTOM AGENT STRING"
remotePeerInfo.agentVersion = customAgentVersion
msListen.addHandler(IdentifyCodec, identifyProto1)
proc acceptHandler(): Future[void] {.async, gcsafe.} =
let c = await transport1.accept()
await msListen.handle(c)
acceptFut = acceptHandler()
conn = await transport2.dial(transport1.addrs[0])
discard await msDial.select(conn, IdentifyCodec)
let id = await identifyProto2.identify(conn, remotePeerInfo.peerId)
check id.pubkey.get() == remoteSecKey.getPublicKey().get()
check id.addrs == ma
check id.protoVersion.get() == ProtoVersion
check id.agentVersion.get() == customAgentVersion
check id.protos == @["/test/proto1/1.0.0", "/test/proto2/1.0.0"]
check id.signedPeerRecord.isNone()
asyncTest "handle failed identify":
msListen.addHandler(IdentifyCodec, identifyProto1)
proc acceptHandler() {.async.} =
var conn: Connection
try:
conn = await transport1.accept()
await msListen.handle(conn)
except CatchableError:
discard
finally:
await conn.close()
acceptFut = acceptHandler()
conn = await transport2.dial(transport1.addrs[0])
expect IdentityNoMatchError:
let pi2 = PeerInfo.new(PrivateKey.random(ECDSA, rng[]).get())
discard await msDial.select(conn, IdentifyCodec)
discard await identifyProto2.identify(conn, pi2.peerId)
asyncTest "can send signed peer record":
msListen.addHandler(IdentifyCodec, identifyProto1)
identifyProto1.sendSignedPeerRecord = true
proc acceptHandler(): Future[void] {.async, gcsafe.} =
let c = await transport1.accept()
await msListen.handle(c)
acceptFut = acceptHandler()
conn = await transport2.dial(transport1.addrs[0])
discard await msDial.select(conn, IdentifyCodec)
let id = await identifyProto2.identify(conn, remotePeerInfo.peerId)
check id.pubkey.get() == remoteSecKey.getPublicKey().get()
check id.addrs == ma
check id.protoVersion.get() == ProtoVersion
check id.agentVersion.get() == AgentVersion
check id.protos == @["/test/proto1/1.0.0", "/test/proto2/1.0.0"]
check id.signedPeerRecord.get() == remotePeerInfo.signedPeerRecord.envelope
suite "handle push identify message":
var
switch1 {.threadvar.}: Switch
switch2 {.threadvar.}: Switch
identifyPush1 {.threadvar.}: IdentifyPush
identifyPush2 {.threadvar.}: IdentifyPush
conn {.threadvar.}: Connection
asyncSetup:
switch1 = newStandardSwitch(sendSignedPeerRecord=true)
switch2 = newStandardSwitch(sendSignedPeerRecord=true)
proc updateStore1(peerId: PeerId, info: IdentifyInfo) {.async.} =
switch1.peerStore.updatePeerInfo(info)
proc updateStore2(peerId: PeerId, info: IdentifyInfo) {.async.} =
switch2.peerStore.updatePeerInfo(info)
identifyPush1 = IdentifyPush.new(updateStore1)
identifyPush2 = IdentifyPush.new(updateStore2)
switch1.mount(identifyPush1)
switch2.mount(identifyPush2)
await switch1.start()
await switch2.start()
conn = await switch2.dial(
switch1.peerInfo.peerId,
switch1.peerInfo.addrs,
IdentifyPushCodec)
check:
switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs
switch2.peerStore[AddressBook][switch1.peerInfo.peerId] == switch1.peerInfo.addrs
switch1.peerStore[KeyBook][switch2.peerInfo.peerId] == switch2.peerInfo.publicKey
switch2.peerStore[KeyBook][switch1.peerInfo.peerId] == switch1.peerInfo.publicKey
switch1.peerStore[AgentBook][switch2.peerInfo.peerId] == switch2.peerInfo.agentVersion
switch2.peerStore[AgentBook][switch1.peerInfo.peerId] == switch1.peerInfo.agentVersion
switch1.peerStore[ProtoVersionBook][switch2.peerInfo.peerId] == switch2.peerInfo.protoVersion
switch2.peerStore[ProtoVersionBook][switch1.peerInfo.peerId] == switch1.peerInfo.protoVersion
switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] == switch2.peerInfo.protocols
switch2.peerStore[ProtoBook][switch1.peerInfo.peerId] == switch1.peerInfo.protocols
switch1.peerStore[SPRBook][switch2.peerInfo.peerId] == switch2.peerInfo.signedPeerRecord.envelope
switch2.peerStore[SPRBook][switch1.peerInfo.peerId] == switch1.peerInfo.signedPeerRecord.envelope
proc closeAll() {.async.} =
await conn.close()
await switch1.stop()
await switch2.stop()
asyncTest "simple push identify":
switch2.peerInfo.protocols.add("/newprotocol/")
switch2.peerInfo.listenAddrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet())
await switch2.peerInfo.update()
check:
switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs
switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] != switch2.peerInfo.protocols
await identifyPush2.push(switch2.peerInfo, conn)
checkExpiring: switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] == switch2.peerInfo.protocols
checkExpiring: switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs
await closeAll()
# Wait the very end to be sure that the push has been processed
check:
switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] == switch2.peerInfo.protocols
switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs
asyncTest "wrong peer id push identify":
switch2.peerInfo.protocols.add("/newprotocol/")
switch2.peerInfo.listenAddrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet())
await switch2.peerInfo.update()
check:
switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs
switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] != switch2.peerInfo.protocols
let oldPeerId = switch2.peerInfo.peerId
switch2.peerInfo = PeerInfo.new(PrivateKey.random(newRng()[]).get())
await identifyPush2.push(switch2.peerInfo, conn)
# We have no way to know when the message will is received
# because it will fail validation inside push identify itself
#
# So no choice but to sleep
await sleepAsync(10.milliseconds)
await closeAll()
# Wait the very end to be sure that the push has been processed
check:
switch1.peerStore[ProtoBook][oldPeerId] != switch2.peerInfo.protocols
switch1.peerStore[AddressBook][oldPeerId] != switch2.peerInfo.addrs