Skip to content

Conversation

@StefanBratanov
Copy link
Contributor

@StefanBratanov StefanBratanov commented May 23, 2025

PR Description

Add QUIC support

Default QUIC ports to 9100 (IPv4) and 9190 (IPv6) when dual-stack.

Fixed Issue(s)

N/A

Documentation

  • I thought about documentation and added the doc-change-required label to this PR if updates are required.

Changelog

  • I thought about adding a changelog entry, and added one if I deemed necessary.

@tbenr
Copy link
Contributor

tbenr commented May 23, 2025

I managed to run it on a 2 node interop and i get

2025-05-23 18:25:27.609 WARN  - Failed to initialize a channel. Closing: (77398ec10259844dd9c9426a9d40ada12d30e856)[id: 0x8d44b8eb, L:QuicConnectionAddress{connId=77398ec10259844dd9c9426a9d40ada12d30e856} ! R:QuicConnectionAddress{connId=}]
kotlin.UninitializedPropertyAccessException: lateinit property muxerSession has not been initialized
at io.libp2p.transport.implementation.ConnectionOverNetty.muxerSession(ConnectionOverNetty.kt:34) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.pubsub.gossip.Gossip.handleConnection(Gossip.kt:53) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.etc.BroadcastConnectionHandler.handleConnection(BroadcastConnectionHandler.kt:10) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.etc.BroadcastConnectionHandler.handleConnection(BroadcastConnectionHandler.kt:10) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.transport.quic.QuicTransport$serverTransportBuilder$2.initChannel(QuicTransport.kt:351) ~[jvm-libp2p-develop.jar:?]
at io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:129) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:112) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannelHandlerContext.callHandlerAdded(AbstractChannelHandlerContext.java:1002) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:558) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.access$100(DefaultChannelPipeline.java:45) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1482) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1136) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:599) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe$2.operationComplete(AbstractChannel.java:383) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe$2.operationComplete(AbstractChannel.java:374) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:603) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:570) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:505) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:649) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:638) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:110) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPromise.setSuccess(DefaultChannelPromise.java:78) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPromise.setSuccess(DefaultChannelPromise.java:73) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel.doRegister(AbstractChannel.java:968) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:408) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.register(AbstractChannel.java:346) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:119) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:113) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.incubator.codec.quic.QuicheQuicServerCodec.handleServer(QuicheQuicServerCodec.java:277) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicServerCodec.quicPacketRead(QuicheQuicServerCodec.java:119) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicCodec$QuicCodecHeaderProcessor.process(QuicheQuicCodec.java:362) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicHeaderParser.parse(QuicHeaderParser.java:142) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicCodec.handleQuicPacket(QuicheQuicCodec.java:200) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicCodec.channelRead(QuicheQuicCodec.java:191) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:100) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:383) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:577) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:552) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:493) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:470) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:204) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:175) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1073) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at java.base/java.lang.Thread.run(Thread.java:1583) [?:?]

@tbenr
Copy link
Contributor

tbenr commented May 23, 2025

I also had to add

in our build

implementation "io.netty.incubator:netty-incubator-codec-native-quic::osx-aarch_64"

native libs are not explicitly set as implementation dependencies in the libp2p project

@rolfyone rolfyone added the DO NOT MERGE Not ready to merge label May 23, 2025
@StefanBratanov
Copy link
Contributor Author

I managed to run it on a 2 node interop and i get

2025-05-23 18:25:27.609 WARN  - Failed to initialize a channel. Closing: (77398ec10259844dd9c9426a9d40ada12d30e856)[id: 0x8d44b8eb, L:QuicConnectionAddress{connId=77398ec10259844dd9c9426a9d40ada12d30e856} ! R:QuicConnectionAddress{connId=}]
kotlin.UninitializedPropertyAccessException: lateinit property muxerSession has not been initialized
at io.libp2p.transport.implementation.ConnectionOverNetty.muxerSession(ConnectionOverNetty.kt:34) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.pubsub.gossip.Gossip.handleConnection(Gossip.kt:53) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.etc.BroadcastConnectionHandler.handleConnection(BroadcastConnectionHandler.kt:10) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.etc.BroadcastConnectionHandler.handleConnection(BroadcastConnectionHandler.kt:10) ~[jvm-libp2p-develop.jar:?]
at io.libp2p.transport.quic.QuicTransport$serverTransportBuilder$2.initChannel(QuicTransport.kt:351) ~[jvm-libp2p-develop.jar:?]
at io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:129) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:112) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannelHandlerContext.callHandlerAdded(AbstractChannelHandlerContext.java:1002) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:558) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.access$100(DefaultChannelPipeline.java:45) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1482) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1136) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:599) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe$2.operationComplete(AbstractChannel.java:383) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe$2.operationComplete(AbstractChannel.java:374) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:603) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:570) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:505) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:649) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:638) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:110) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPromise.setSuccess(DefaultChannelPromise.java:78) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPromise.setSuccess(DefaultChannelPromise.java:73) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel.doRegister(AbstractChannel.java:968) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:408) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.register(AbstractChannel.java:346) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:119) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:113) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.incubator.codec.quic.QuicheQuicServerCodec.handleServer(QuicheQuicServerCodec.java:277) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicServerCodec.quicPacketRead(QuicheQuicServerCodec.java:119) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicCodec$QuicCodecHeaderProcessor.process(QuicheQuicCodec.java:362) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicHeaderParser.parse(QuicHeaderParser.java:142) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicCodec.handleQuicPacket(QuicheQuicCodec.java:200) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.incubator.codec.quic.QuicheQuicCodec.channelRead(QuicheQuicCodec.java:191) ~[netty-incubator-codec-classes-quic-0.0.71.Final.jar:0.0.71.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:100) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:383) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:577) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:552) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:493) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:470) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:204) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:175) ~[netty-transport-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1073) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.2.0.Final.jar:4.2.0.Final]
at java.base/java.lang.Thread.run(Thread.java:1583) [?:?]

I get the same when testing. @Nashatyrev any idea? In QuicServer#serverTransportBuilder, I can see the muxer not set? Any idea what is the best way to fix

@Nashatyrev
Copy link
Contributor

What I see in QuicTransport is that ConnectionOverNetty.setMuxerSession() is called in the dial() method only but I don't get where it is called when a server side handler is created 🤔

@Nashatyrev
Copy link
Contributor

Quic tests are working because on the server side Connection.muxerSession is not invoked.
The QuicTransport implementation is quite new and is not well test covered, so I would be cautious adding it to Teku

@StefanBratanov
Copy link
Contributor Author

Quic tests are working because on the server side Connection.muxerSession is not invoked. The QuicTransport implementation is quite new and is not well test covered, so I would be cautious adding it to Teku

Yeah, we are just experimenting. So I suppose the muxer should also be set on the server side.

@github-actions
Copy link

github-actions bot commented Sep 11, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@Nashatyrev
Copy link
Contributor

I have read the CLA Document and I hereby sign the CLA

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO NOT MERGE Not ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants