Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circuit relay v1 #670

Merged
merged 2 commits into from
May 18, 2022
Merged

Circuit relay v1 #670

merged 2 commits into from
May 18, 2022

Conversation

lchenut
Copy link
Contributor

@lchenut lchenut commented Dec 9, 2021

A simple way to make it work at the moment:

proc main() {.async, gcsafe.} =
  let
    rng = newRng()
    src = newStandardSwitch(rng=rng)
    rel = newStandardSwitch(rng=rng)
    address = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet()
    addressRelay = MultiAddress.init("/ip4/127.0.0.1/tcp/0/p2p-circuit").tryGet()
    dst = SwitchBuilder
      .new()
      .withRng(rng)
      .withAddresses(@[ address, addressRelay ])
      .withTcpTransport()
      .withMplex()
      .withNoise()
      .build()
    pingProtocol = Ping.new(rng=rng)
    relaySrc = Relay.new(src, false)
    relayRel = Relay.new(rel, true)
    relayDst = Relay.new(dst, false)

  src.mount(relaySrc)
  rel.mount(relayRel)
  dst.mount(relayDst)
  dst.mount(pingProtocol)
  src.transports &= RelayTransport.new(relaySrc)
  ((Dialer)src.dialer).transports = src.transports
  dst.transports &= RelayTransport.new(relayDst)
  ((Dialer)dst.dialer).transports = dst.transports

  let
    srcFut = await src.start()
    relFut = await rel.start()
    dstFut = await dst.start()

  let ma = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" & $rel.peerInfo.peerId & "/p2p-circuit/p2p/" & $dst.peerInfo.peerId).tryGet()
  await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
  await rel.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
  let conn = await src.dial(dst.peerInfo.peerId, @[ ma ], PingCodec)

  echo "ping: ", await pingProtocol.ping(conn)

  await allFutures(src.stop(), rel.stop(), dst.stop())
  await allFutures(srcFut & relFut & dstFut)
waitFor(main())

Few notes:

  • The destination having two multiaddresses is clearly undesirable but it's a temporary workaround because without circuit-relay address, the transport won't start.
  • Speaking of temporary workaround, Dial.transports becoming public is one.
  • It may be interesting to create an access control list as it is implemented in the go-libp2p version even though there's no mention of it in the specs. It's relatively easy to implement.

libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
Copy link
Contributor

@dryajov dryajov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @lchenut! Thank you so much for taking the time to work on this! Great job and appologies for taking this long to respond from my side!

So far everything looks pretty good sans a few minor things I've already commented on. In any case I'll give it another pass soon.

One crussial thing that is missing are interop tests. We have examples of how we do this in the testinterop.nim file, we run them against a go libp2p daemon instance. It's very usefull in catching any inconsistencies and validate how well supported the protocol. Let me know if you need any help navigating it.

Cheers!

libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
tests/testrelay.nim Outdated Show resolved Hide resolved
Copy link
Contributor

@Menduist Menduist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nitpicks

libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
@lchenut
Copy link
Contributor Author

lchenut commented Apr 15, 2022

@dryajov @Menduist, I corrected all the errors / nitpicks and I added the interop tests. The only thing I left open is the dirty buffers in the bridge part of the relay as I wanted your advice on this point.
The new way to make it works could be this:

proc main() {.async, gcsafe.} =
  let
    CustomProtoCodec = "/customProto"
    rng = newRng()
    src = SwitchBuilder.new()
      .withRng(rng)
      .withAddresses(@[ MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet() ])
      .withTcpTransport()
      .withMplex()
      .withNoise()
      .withRelayTransport(canHop=false)
      .build()
    rel = SwitchBuilder.new()
      .withRng(rng)
      .withAddresses(@[ MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet() ])
      .withTcpTransport()
      .withMplex()
      .withNoise()
      .withRelayTransport(canHop=true)
      .build()
    dst = SwitchBuilder.new()
      .withRng(rng)
      .withAddresses(@[ MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet() ])
      .withTcpTransport()
      .withMplex()
      .withNoise()
      .withRelayTransport(canHop=false)
      .build()

  # Create a custom protocol
  var proto = new LPProtocol
  proto.handler = proc (conn: Connection, customProto: string) {.async.} =
    echo "Destination Read From Source: ", string.fromBytes(await conn.readLP(1024))
    await conn.writeLp("I'm out")
    await conn.close()
  proto.codec = CustomProtoCodec

  dst.mount(proto)

  await src.start()
  await rel.start()
  await dst.start()

  let ma = MultiAddress.init($rel.peerInfo.addrs[0] & "/p2p/" & $rel.peerInfo.peerId & "/p2p-circuit/p2p/" & $dst.peerInfo.peerId).tryGet()
  # /ip4/.../tcp/.../p2p/QmRelay/p2p-circuit/p2p/QmDestination
  await src.connect(rel.peerInfo.peerId, rel.peerInfo.addrs)
  await rel.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
  let conn = await src.dial(dst.peerInfo.peerId, @[ ma ], CustomProtoCodec)

  await conn.writeLp("Hello")
  echo "Source Read From Destination: ", string.fromBytes(await conn.readLp(1024))

  await allFutures(src.stop(), rel.stop(), dst.stop())
waitFor(main())

Few more points:

  • This test is really redundant with the previous one, I was originally testing the withRelayTransport of the builder and decide to keep it (more tests is (nearly) always better)
  • Speaking of the builder, this part is really dirty (still cleaner than the old version though) and hiding the Relay behind the switch prevents us to change the three configurable variables (number maximum of circuit, number maximum of circuit per peer and message size)
  • There's always this ACL thing, not mentioned in the spec, that the go version does
  • This is my bad, I fix it now

libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
@lchenut
Copy link
Contributor Author

lchenut commented May 5, 2022

@dryajov @Menduist I fixed the few minor errors I mentioned at the last meeting. If you could review the code that would be great.

libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
libp2p/protocols/relay.nim Outdated Show resolved Hide resolved
@Menduist Menduist marked this pull request as ready for review May 9, 2022 09:01
@Menduist Menduist requested review from dryajov and Menduist May 9, 2022 09:01
Copy link
Contributor

@Menduist Menduist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting close!

libp2p/dial.nim Outdated Show resolved Hide resolved
libp2p/switch.nim Show resolved Hide resolved
libp2p/switch.nim Show resolved Hide resolved
@Menduist Menduist changed the title [WIP] Circuit relay Circuit relay v1 May 10, 2022
Copy link
Contributor

@dryajov dryajov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job @lchenut! LGTM!

@lchenut lchenut merged commit 13503f3 into vacp2p:unstable May 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants