Identify Push (#587)

* start of identifypush

* better pushidentify

* push identify test

* fix: make peerid optional
This commit is contained in:
Tanguy Cizain 2021-06-14 19:08:47 +02:00 committed by GitHub
parent bd2e9a0462
commit bed00ec43c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 151 additions and 6 deletions

View File

@ -13,6 +13,7 @@ import options
import chronos, chronicles
import ../protobuf/minprotobuf,
../peerinfo,
../connmanager,
../stream/connection,
../peerid,
../crypto/crypto,
@ -30,8 +31,6 @@ const
ProtoVersion* = "ipfs/0.1.0"
AgentVersion* = "nim-libp2p/0.0.1"
#TODO: implement push identify, leaving out for now as it is not essential
type
IdentifyError* = object of LPError
IdentityNoMatchError* = object of IdentifyError
@ -49,6 +48,9 @@ type
Identify* = ref object of LPProtocol
peerInfo*: PeerInfo
IdentifyPush* = ref object of LPProtocol
connManager: ConnManager
proc encodeMsg*(peerInfo: PeerInfo, observedAddr: Multiaddress): ProtoBuffer
{.raises: [Defect, IdentifyNoPubKeyError].} =
result = initProtoBuffer()
@ -160,7 +162,57 @@ proc identify*(p: Identify,
raise newException(IdentityNoMatchError, "Peer ids don't match")
proc push*(p: Identify, conn: Connection) {.async.} =
await conn.write(IdentifyPushCodec)
var pb = encodeMsg(p.peerInfo, conn.observedAddr)
proc new*(T: typedesc[IdentifyPush], connManager: ConnManager): T =
let identifypush = T(connManager: connManager)
identifypush.init()
identifypush
proc init*(p: IdentifyPush) =
proc handle(conn: Connection, proto: string) {.async, gcsafe, closure.} =
trace "handling identify push", conn
try:
var message = await conn.readLp(64*1024)
let infoOpt = decodeMsg(message)
if infoOpt.isNone():
raise newException(IdentityInvalidMsgError, "Incorrect message received!")
let indentInfo = infoOpt.get()
if isNil(conn.peerInfo):
raise newException(IdentityInvalidMsgError, "Connection got no peerInfo")
if indentInfo.pubKey.isSome:
let receivedPeerId = PeerID.init(indentInfo.pubKey.get()).tryGet()
if receivedPeerId != conn.peerInfo.peerId:
raise newException(IdentityNoMatchError, "Peer ids don't match")
if indentInfo.addrs.len > 0:
conn.peerInfo.addrs = indentInfo.addrs
if indentInfo.agentVersion.isSome:
conn.peerInfo.agentVersion = indentInfo.agentVersion.get()
if indentInfo.protoVersion.isSome:
conn.peerInfo.protoVersion = indentInfo.protoVersion.get()
if indentInfo.protos.len > 0:
conn.peerInfo.protocols = indentInfo.protos
trace "triggering peer event", peerInfo = conn.peerInfo
await p.connManager.triggerPeerEvents(conn.peerInfo, PeerEvent(kind: PeerEventKind.Identified))
except CancelledError as exc:
raise exc
except CatchableError as exc:
info "exception in identify push handler", exc = exc.msg, conn
finally:
trace "exiting identify push handler", conn
await conn.closeWithEOF()
p.handler = handle
p.codec = IdentifyPushCodec
proc push*(p: IdentifyPush, peerInfo: PeerInfo, conn: Connection) {.async.} =
var pb = encodeMsg(peerInfo, conn.observedAddr)
await conn.writeLp(pb.buffer)

View File

@ -1,5 +1,5 @@
import options, bearssl
import chronos, strutils
import chronos, strutils, sequtils, sets, algorithm
import ../libp2p/[protocols/identify,
multiaddress,
peerinfo,
@ -7,6 +7,8 @@ import ../libp2p/[protocols/identify,
stream/connection,
multistream,
transports/transport,
switch,
builders,
transports/tcptransport,
crypto/crypto,
upgrademngrs/upgrade]
@ -118,3 +120,94 @@ suite "Identify":
let pi2 = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
discard await msDial.select(conn, IdentifyCodec)
discard await identifyProto2.identify(conn, pi2)
suite "handle push identify message":
var
switch1 {.threadvar.}: Switch
switch2 {.threadvar.}: Switch
identifyPush1 {.threadvar.}: IdentifyPush
identifyPush2 {.threadvar.}: IdentifyPush
awaiters {.threadvar.}: seq[Future[void]]
conn {.threadvar.}: Connection
asyncSetup:
switch1 = newStandardSwitch()
switch2 = newStandardSwitch()
identifyPush1 = IdentifyPush.new(switch1.connManager)
identifyPush2 = IdentifyPush.new(switch2.connManager)
switch1.mount(identifyPush1)
switch2.mount(identifyPush2)
awaiters.add(await switch1.start())
awaiters.add(await switch2.start())
conn = await switch2.dial(switch1.peerInfo.peerId, switch1.peerInfo.addrs, IdentifyPushCodec)
let storedInfo1 = switch1.peerStore.get(switch2.peerInfo.peerId)
let storedInfo2 = switch2.peerStore.get(switch1.peerInfo.peerId)
check:
storedInfo1.peerId == switch2.peerInfo.peerId
storedInfo2.peerId == switch1.peerInfo.peerId
storedInfo1.addrs.toSeq() == switch2.peerInfo.addrs
storedInfo2.addrs.toSeq() == switch1.peerInfo.addrs
storedInfo1.protos.toSeq() == switch2.peerInfo.protocols
storedInfo2.protos.toSeq() == switch1.peerInfo.protocols
proc closeAll() {.async.} =
await conn.close()
await switch1.stop()
await switch2.stop()
# this needs to go at end
await allFuturesThrowing(awaiters)
asyncTest "simple push identify":
switch2.peerInfo.protocols.add("/newprotocol/")
switch2.peerInfo.addrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet())
check:
switch1.peerStore.get(switch2.peerInfo.peerId).addrs.toSeq() != switch2.peerInfo.addrs
switch1.peerStore.get(switch2.peerInfo.peerId).protos != switch2.peerInfo.protocols.toSet()
await identifyPush2.push(switch2.peerInfo, conn)
await closeAll()
# Wait the very end to be sure that the push has been processed
var aprotos = switch1.peerStore.get(switch2.peerInfo.peerId).protos.toSeq()
var bprotos = switch2.peerInfo.protocols
aprotos.sort()
bprotos.sort()
check:
aprotos == bprotos
switch1.peerStore.get(switch2.peerInfo.peerId).addrs == switch2.peerInfo.addrs.toSet()
asyncTest "wrong peer id push identify":
switch2.peerInfo.protocols.add("/newprotocol/")
switch2.peerInfo.addrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet())
check:
switch1.peerStore.get(switch2.peerInfo.peerId).addrs != switch2.peerInfo.addrs.toSet()
switch1.peerStore.get(switch2.peerInfo.peerId).protos.toSeq() != switch2.peerInfo.protocols
let oldPeerId = switch2.peerInfo.peerId
switch2.peerInfo = PeerInfo.init(PrivateKey.random(newRng()[]).get())
await identifyPush2.push(switch2.peerInfo, conn)
await closeAll()
# Wait the very end to be sure that the push has been processed
var aprotos = switch1.peerStore.get(oldPeerId).protos.toSeq()
var bprotos = switch2.peerInfo.protocols
aprotos.sort()
bprotos.sort()
check:
aprotos != bprotos
switch1.peerStore.get(oldPeerId).addrs.toSeq() != switch2.peerInfo.addrs