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

feat(transport): add experimental QUIC Transport (not production ready) #725

Merged
merged 48 commits into from
Sep 12, 2024

Conversation

Menduist
Copy link
Contributor

@Menduist Menduist commented Jun 1, 2022

Our quic effort is blocked by bearssl not supporting TLS1.3, but since Mark did most of the work to implement Quic here: #563 and on nim-quic, this PR is going to bring encryption-less Quic into nim-libp2p
This allows us to test it, and make sure it doesn't bitrot.

Heavily WiP:

  • Extract code from QUIC transport #563
  • Create custom muxer & upgrader
  • Basic E2E switch test working
  • Update nim-quic to get address informations in libp2p (for observed address and port 0 resolving)
  • More tests
  • Cleanup

Since encryption is not yet supported, we're not compatible with any other libp2ps, and have to rely on home made protocols to retrieve the peer's id

Co-authored-by: markspanbroek <mark@spanbroek.net>
@Menduist
Copy link
Contributor Author

Menduist commented Aug 3, 2022

Unfortunately, nim-quic relies on questionable which doesn't work on nim devel
(ref codex-storage/questionable#17)

So even though this branch works, it should not be merged until this get fixed
(otherwise, this will break our daily CI tests)

@dryajov
Copy link
Contributor

dryajov commented Aug 3, 2022

We should not be using questionable in a low level library such as nim-quic, in fact, we should keep the amount of external dependencies to an absolute minimum.

Questionable and the likes, are totally fine in a high level application, where the amount of "busyness" related logic might become high (Codex, Nimbus, etc...), but not in a low level dependency such as libp2p or a transport.

@diegomrsantos diegomrsantos self-assigned this Jun 26, 2024
@diegomrsantos diegomrsantos changed the title feat(transport): add QUIC Transport feat(transport): add experimental QUIC Transport (not production ready) Sep 5, 2024
_: type QuicStream, stream: Stream, oaddr: Opt[MultiAddress], peerId: PeerId
): QuicStream =
let quicstream = QuicStream(stream: stream, observedAddr: oaddr, peerId: peerId)
procCall P2PConnection(quicstream).initStream()
Copy link
Collaborator

Choose a reason for hiding this comment

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

You should specify an objName for quicstream before calling initStream. https://github.com/vacp2p/nim-libp2p/blob/master/libp2p/stream/connection.nim#L56-L57

Comment on lines +40 to +43
except QuicError:
raise newLPStreamEOFError()
except CatchableError:
raise newLPStreamEOFError()
Copy link
Collaborator

@lchenut lchenut Sep 6, 2024

Choose a reason for hiding this comment

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

After a recent discussion with @Ivansete-status, I think those errors need a small rework, they lack precision (not in this PR though). But nevertheless, everytime you use LPStreamEOFError you should try to use one of those error instead.

Comment on lines +72 to +74
# Session
type QuicSession* = ref object of P2PConnection
connection: QuicConnection
Copy link
Collaborator

@lchenut lchenut Sep 6, 2024

Choose a reason for hiding this comment

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

I'm not sure to understand why you need two P2PConnections here (with QuicSession and QuicStream). It's a bit confusing. QuicSession looks like ConnManager to me.

And I think it's better to create your custom Connection in libp2p/streams instead of here.


# Stream
type QuicStream* = ref object of P2PConnection
stream: Stream
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not a huge fan of this un-prefixed Stream. Maybe renaming it QuicStream and renaming the current QuicStream into LPQuicStream will be clearer.

handleFut: Future[void]

method newStream*(
m: QuicMuxer, name: string = "", lazy: bool = false
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think the lazy flag is an option here. Maybe add a log if someone tries to use it.

try:
while not m.quicSession.atEof:
let incomingStream = await m.quicSession.getStream(Direction.In)
asyncSpawn m.handleStream(incomingStream)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If you find an alternative to the asyncspawn, it would be great.

type QuicUpgrade = ref object of Upgrade

type QuicTransport* = ref object of Transport
listener: Listener
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as above, not a fan of un-prefixed object like that. QuicListener is great.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is defined in nim-quic.

QUIC_V1.match(address)

method start*(transport: QuicTransport, addrs: seq[MultiAddress]) {.async.} =
doAssert transport.listener.isNil, "start() already called"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this really be a doAssert? Raising an LPError should be a better idea.

Comment on lines +163 to +164
for c in transport.connections:
await c.close()
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about something like that: await allFutures(transport.connections.mapIt(it.close))

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any semantic difference? Not sure if it adds enough value to justify the change.

Comment on lines +201 to +202
let connection = await dial(initTAddress(address).tryGet)
return transport.wrapConnection(connection)
Copy link
Collaborator

@lchenut lchenut Sep 6, 2024

Choose a reason for hiding this comment

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

You should probably check if transport.running == true

@diegomrsantos diegomrsantos marked this pull request as ready for review September 12, 2024 09:14
Copy link
Collaborator

@lchenut lchenut left a comment

Choose a reason for hiding this comment

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

Approved in order to work on the comments in separate/smaller PRs.

@diegomrsantos diegomrsantos added this pull request to the merge queue Sep 12, 2024
Merged via the queue into master with commit b37133c Sep 12, 2024
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: done
Development

Successfully merging this pull request may close these issues.

4 participants