[skip ci] Debug new discovery tuto

This commit is contained in:
Ludovic Chenut 2022-10-21 17:53:41 +02:00
parent 8d1c81776e
commit 429dc8e71b
No known key found for this signature in database
GPG Key ID: D9A59B1907F1D50C
4 changed files with 124 additions and 34 deletions

View File

@ -6,8 +6,8 @@
## we'll try to discover a specific peer to ping on the network. ## we'll try to discover a specific peer to ping on the network.
## ##
## First, as usual, we import the dependencies: ## First, as usual, we import the dependencies:
import sequtils
import chronos import chronos
import stew/byteutils
import libp2p import libp2p
import libp2p/protocols/rendezvous import libp2p/protocols/rendezvous
@ -30,63 +30,138 @@ proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch =
.withRendezVous(rdv) .withRendezVous(rdv)
.build() .build()
const DumbCodec = "/dumb/proto/1.0.0"
type DumbProto = ref object of LPProtocol
proc new(T: typedesc[DumbProto], nodeNumber: int): T =
proc handle(conn: Connection, proto: string) {.async, gcsafe.} =
echo "Node", nodeNumber, " received: ", string.fromBytes(await conn.readLp(1024))
await conn.close()
return T(codecs: @[DumbCodec], handler: handle)
## We can create our main procedure: ## We can create our main procedure:
proc main() {.async, gcsafe.} = proc main() {.async, gcsafe.} =
# Create a "network" of six nodes looking like that: # First of all, we'll create and start a boot node that'll be
# node0 <-> node1 <-> node2 <-> node3 <-> node4 <-> node5 # used as an information hub on the network
let bootNode = createSwitch()
await bootNode.start()
var var
switches: seq[Switch] = @[] switches: seq[Switch] = @[]
discManagers: seq[DiscoveryManager] = @[] discManagers: seq[DiscoveryManager] = @[]
for _ in 0..5:
for i in 0..5:
# Create a RendezVous Protocol # Create a RendezVous Protocol
let rdv = RendezVous.new() let rdv = RendezVous.new()
# Create a switch, mount the RendezVous protocol to it, start it and # Create a switch, mount the RendezVous protocol to it, start it and
# enventually connect it to the previous node in the sequence # eventually connect it to the bootNode
let switch = createSwitch(rdv) let switch = createSwitch(rdv)
switch.mount(DumbProto.new(i))
await switch.start() await switch.start()
if switches.len > 0: await switch.connect(bootNode.peerInfo.peerId, bootNode.peerInfo.addrs)
await switches[^1].connect(switch.peerInfo.peerId, switch.peerInfo.addrs)
switches.add(switch) switches.add(switch)
# A discovery manager is a simple tool, you setup it by adding discovery # A discovery manager is a simple tool, you set it up by adding discovery
# interfaces (such as RendezVousInterface) then you can use it to advertise # interfaces (such as RendezVousInterface) then you can use it to advertise
# something on the network or to request something from it. # something on the network or to request something from it.
let dm = DiscoveryManager() let dm = DiscoveryManager()
# A RendezVousInterface is a RendezVous protocol wrapped to be usable by the # A RendezVousInterface is a RendezVous protocol wrapped to be usable by the
# DiscoveryManager. You can initialize a time to advertise/request (tta/ttr) # DiscoveryManager. You can initialize a time to advertise/request (tta/ttr)
# for advertise/request every x seconds. # for advertise/request every x seconds.
dm.add(RendezVousInterface.new(rdv, ttr = 250.milliseconds)) dm.add(RendezVousInterface.new(rdv))
# Each nodes of the network'll advertise on some topics (even gang or odd club)
if i mod 2 == 0:
dm.advertise(RdvNamespace("Even Gang"))
else:
dm.advertise(RdvNamespace("Odd Club"))
discManagers.add(dm) discManagers.add(dm)
# The first node of the network advertise on someTopic
discManagers[0].advertise(RdvNamespace("someTopic"))
for i in 1..4:
# All the four "middle" nodes request informations on someTopic
# to make the message spread. With a time to request of 250ms, it should
# spread on the four nodes in a little over 1 second.
discard discManagers[i].request(RdvNamespace("someTopic"))
let let
# The ending node request on someTopic aswell and await for information. rdv = RendezVous.new()
query = discManagers[5].request(RdvNamespace("someTopic")) newcomer = createSwitch(rdv)
# getPeer give you a PeerAttribute containing informations about the peer. dm = DiscoveryManager()
# The most useful are the PeerId and the MultiAddresses await newcomer.start()
res = await query.getPeer() await newcomer.connect(bootNode.peerInfo.peerId, bootNode.peerInfo.addrs)
dm.add(RendezVousInterface.new(rdv, ttr = 250.milliseconds))
doAssert(res[PeerId] == switches[0].peerInfo.peerId) let query = dm.request(RdvNamespace("Odd Club"))
let resMa = res.getAll(MultiAddress) for _ in 0..2:
for ma in resMa: echo "start"
doAssert(ma in switches[0].peerInfo.addrs) let
echo "Peer Found: ", res[PeerId], " ", resMa res = await query.getPeer()
# The peer Id and the address of the node0 is discovered by the node5 after echo "0 ", res[PeerId], " ", res.getAll(MultiAddress)
# being pass by all the intermediate node. let
conn = await newcomer.dial(res[PeerId], res.getAll(MultiAddress), DumbCodec)
echo "1"
await conn.writeLp("Odd Club suuuucks! Even Gang is better!")
echo "2"
await sleepAsync(300.milliseconds)
await conn.close()
echo "stop"
query.stop()
# The node5 can connect the node0 to talk about someTopic directly.
# Stop all the DiscoveryManagers
for dm in discManagers: dm.stop()
# Stop all the switches # # Create a "network" of six nodes looking like that:
let futStop = switches.mapIt(it.stop()) # # node0 <-> node1 <-> node2 <-> node3 <-> node4 <-> node5
await allFutures(futStop) # var
# switches: seq[Switch] = @[]
# discManagers: seq[DiscoveryManager] = @[]
# for _ in 0..5:
# # Create a RendezVous Protocol
# let rdv = RendezVous.new()
# # Create a switch, mount the RendezVous protocol to it, start it and
# # enventually connect it to the previous node in the sequence
# let switch = createSwitch(rdv)
# if switches.len == 0:
#
# await switch.start()
# if switches.len > 0:
# await switches[^1].connect(switch.peerInfo.peerId, switch.peerInfo.addrs)
# switches.add(switch)
#
# # A discovery manager is a simple tool, you setup it by adding discovery
# # interfaces (such as RendezVousInterface) then you can use it to advertise
# # something on the network or to request something from it.
# let dm = DiscoveryManager()
# # A RendezVousInterface is a RendezVous protocol wrapped to be usable by the
# # DiscoveryManager. You can initialize a time to advertise/request (tta/ttr)
# # for advertise/request every x seconds.
# dm.add(RendezVousInterface.new(rdv, ttr = 250.milliseconds))
# discManagers.add(dm)
#
# # The first node of the network advertise on someTopic
# discManagers[0].advertise(RdvNamespace("someTopic"))
# for i in 1..4:
# # All the four "middle" nodes request informations on someTopic
# # to make the message spread. With a time to request of 250ms, it should
# # spread on the four nodes in a little over 1 second.
# discard discManagers[i].request(RdvNamespace("someTopic"))
# let
# # The ending node request on someTopic aswell and await for information.
# query = discManagers[5].request(RdvNamespace("someTopic"))
# # getPeer give you a PeerAttribute containing informations about the peer.
# # The most useful are the PeerId and the MultiAddresses
# res = await query.getPeer()
#
# # Now that a peer have been found, we can stop the query
# query.stop()
#
# doAssert(res[PeerId] == switches[0].peerInfo.peerId)
# let resMa = res.getAll(MultiAddress)
# for ma in resMa:
# doAssert(ma in switches[0].peerInfo.addrs)
# echo "Peer Found: ", res[PeerId], " ", resMa
# # The peer Id and the address of the node0 is discovered by the node5 after
# # being pass by all the intermediate node.
#
# # The node5 can connect the node0 to talk about someTopic directly.
#
# # Stop all the DiscoveryManagers
# for dm in discManagers: dm.stop()
#
# # Stop all the switches
# let futStop = switches.mapIt(it.stop())
# await allFutures(futStop)
waitFor(main()) waitFor(main())

View File

@ -90,6 +90,7 @@ task website, "Build the website":
tutorialToMd("examples/tutorial_1_connect.nim") tutorialToMd("examples/tutorial_1_connect.nim")
tutorialToMd("examples/tutorial_2_customproto.nim") tutorialToMd("examples/tutorial_2_customproto.nim")
tutorialToMd("examples/tutorial_3_protobuf.nim") tutorialToMd("examples/tutorial_3_protobuf.nim")
tutorialToMd("examples/tutorial_5_discovery.nim")
tutorialToMd("examples/circuitrelay.nim") tutorialToMd("examples/circuitrelay.nim")
exec "mkdocs build" exec "mkdocs build"

View File

@ -71,25 +71,36 @@ proc select*(m: MultistreamSelect,
else: else:
trace "multistream handshake success", conn trace "multistream handshake success", conn
echo " 0 ", proto
if proto.len() == 0: # no protocols, must be a handshake call if proto.len() == 0: # no protocols, must be a handshake call
return Codec return Codec
else: else:
echo " 1"
s = string.fromBytes(await conn.readLp(MsgSize)) # read the first proto s = string.fromBytes(await conn.readLp(MsgSize)) # read the first proto
echo " 2"
validateSuffix(s) validateSuffix(s)
echo " 3"
trace "reading first requested proto", conn trace "reading first requested proto", conn
if s == proto[0]: if s == proto[0]:
echo " 4.1"
trace "successfully selected ", conn, proto = proto[0] trace "successfully selected ", conn, proto = proto[0]
conn.protocol = proto[0] conn.protocol = proto[0]
echo " 4.2 ", proto[0]
return proto[0] return proto[0]
elif proto.len > 1: elif proto.len > 1:
echo " 5.1"
# Try to negotiate alternatives # Try to negotiate alternatives
let protos = proto[1..<proto.len()] let protos = proto[1..<proto.len()]
trace "selecting one of several protos", conn, protos = protos trace "selecting one of several protos", conn, protos = protos
echo " 5.2"
for p in protos: for p in protos:
echo " 5.2.1"
trace "selecting proto", conn, proto = p trace "selecting proto", conn, proto = p
await conn.writeLp((p & "\n")) # select proto await conn.writeLp((p & "\n")) # select proto
echo " 5.2.2"
s = string.fromBytes(await conn.readLp(MsgSize)) # read the first proto s = string.fromBytes(await conn.readLp(MsgSize)) # read the first proto
validateSuffix(s) validateSuffix(s)
echo " 5.2.3"
if s == p: if s == p:
trace "selected protocol", conn, protocol = s trace "selected protocol", conn, protocol = s
conn.protocol = s conn.protocol = s
@ -102,6 +113,7 @@ proc select*(m: MultistreamSelect,
proc select*(m: MultistreamSelect, proc select*(m: MultistreamSelect,
conn: Connection, conn: Connection,
proto: string): Future[bool] {.async.} = proto: string): Future[bool] {.async.} =
echo proto
if proto.len > 0: if proto.len > 0:
return (await m.select(conn, @[proto])) == proto return (await m.select(conn, @[proto])) == proto
else: else:

View File

@ -76,7 +76,9 @@ proc identify*(
conn: Connection) {.async, gcsafe.} = conn: Connection) {.async, gcsafe.} =
## identify the connection ## identify the connection
echo "==>0", self.identity.codec
if (await self.ms.select(conn, self.identity.codec)): if (await self.ms.select(conn, self.identity.codec)):
echo "==>1"
let let
info = await self.identity.identify(conn, conn.peerId) info = await self.identity.identify(conn, conn.peerId)
peerStore = self.connManager.peerStore peerStore = self.connManager.peerStore