Replies: 7 comments
-
I had been spending some thoughts regarding what approach we should take regarding implementation of QUIC. Questions and Considerations:
It is a very tough choice, using Are the performance benefits worth the cost, I would beg to differ at this point. Rather I would like to go first with the python native approach resulting in a much faster implementation of QUIC, and it has all the features 0-RTT, HTTP/3 support etc. If and when we see a requirement of bringing high-performance QUIC transport, then we can come back here, curse me and start development of a new transport. |
Beta Was this translation helpful? Give feedback.
-
@AkMo3 : Thank you so much for the incredibly thorough and thoughtful breakdown — this is excellent work, and I really appreciate the depth of analysis you’ve brought in here. You've laid out the trade-offs between the two implementation options for QUIC with great clarity, especially factoring in performance, interoperability, and maintainability. The proposed path — starting with On the same note, thanks for also sharing your feedback on the existing efforts on QUIC transport layer within Py-libp2p. Here's why I strongly agree with your approach:
Overall, I’m fully aligned with your proposal to go ahead with Please go ahead and start shaping the transport layer around Let’s keep tracking performance metrics, and if any bottlenecks arise during usage or scaling, we can revisit and prioritize optimization. Thanks again for the clarity and leadership here — delighted to see this move forward. |
Beta Was this translation helpful? Give feedback.
-
Thanks for your thorough review, @AkMo3. I agree with your and @seetadev's view. |
Beta Was this translation helpful? Give feedback.
-
@pacrob : Thank you Paul for your kind feedback and pointers. Appreciate it. |
Beta Was this translation helpful? Give feedback.
-
@AkMo3 , @lla-dane , @guha-rahul : We can generate pytest + trio-based test templates for QUIC support in py-libp2p using pytest-trio. Wish to share some of the test cases we should cover in the QUIC PR. This will also be helpful in transport interop efforts with other libp2p modules: 1. Basic QUIC Handshake and Connection
2. Identity and Peer ID Validation
3. Stream Multiplexing over QUIC
4. Interoperability
5. Error Handling and Recovery
6. Integration with Transport Manager
7. Reconnect and Resilience
8. Unit Tests for Helpers and Internals
9. Code Quality & Linting
10. Coverage
|
Beta Was this translation helpful? Give feedback.
-
QUIC Interoperability Analysis Report
Executive SummaryThis report analyzes QUIC interoperability test results for Python libp2p v0.2.9 against various other libp2p implementations. The tests reveal a critical interoperability issue where Python libp2p fails to interoperate with Go and Rust implementations when acting as a listener, but succeeds when acting as a dialer. QUIC Libraries by Implementation
Test Results Overview
Key Findings✅ Successful Interoperability
❌ Failed Interoperability
Root Cause AnalysisPrimary Issue: "Unhandled event type: ProtocolNegotiated"The most consistent error across all failed tests is:
This error occurs in the Python listener when receiving QUIC protocol negotiation events from Go/Rust dialers. Secondary Issues
Error Pattern AnalysisGo → Python Failures
Rust → Python Failures
Python QUIC Configuration AnalysisCurrent Python QUIC Configuration# Enhanced QUIC transport configuration
quic_config = QUICTransportConfig(
# Disable certificate verification for interoperability
verify_mode=ssl.CERT_NONE,
# Increase timeouts for interoperability testing
idle_timeout=60.0,
connection_timeout=30.0,
# Increase stream timeouts
STREAM_OPEN_TIMEOUT=15.0,
STREAM_ACCEPT_TIMEOUT=30.0,
STREAM_READ_TIMEOUT=30.0,
STREAM_WRITE_TIMEOUT=30.0,
# Increase connection handshake timeout
CONNECTION_HANDSHAKE_TIMEOUT=60.0,
# Enable both QUIC versions for maximum compatibility
enable_draft29=True,
enable_v1=True,
# Enhanced QUIC settings for interoperability
max_idle_timeout=60.0,
keep_alive_interval=30.0,
disable_active_migration=True,
enable_0rtt=True,
# Protocol negotiation settings
enable_protocol_negotiation=True,
alpn_protocols=["libp2p"],
# Connection management
max_concurrent_streams=200,
initial_max_data=104857600,
initial_max_stream_data_bidirectional_local=1048576,
initial_max_stream_data_bidirectional_remote=1048576,
initial_max_streams_bidirectional=100,
initial_max_streams_unidirectional=100
) Host Configuration for QUIC# For QUIC transport, use it as a secure transport (like Java implementation)
# QUIC has built-in security and multiplexing, so no separate security/muxer needed
if enable_quic:
self.host = new_host(
key_pair=key_pair,
muxer_opt=muxer_options,
listen_addrs=[listen_addr],
enable_quic=enable_quic,
quic_transport_opt=quic_config
)
else:
self.host = new_host(
key_pair=key_pair,
sec_opt=security_options,
muxer_opt=muxer_options,
listen_addrs=[listen_addr],
enable_quic=enable_quic,
quic_transport_opt=quic_config
) Hypotheses for Test Failures1. Protocol Negotiation Event HandlingHypothesis: Python libp2p's QUIC implementation doesn't properly handle Evidence: Consistent "Unhandled event type: ProtocolNegotiated" errors across all Go/Rust → Python tests. Root Cause: The Python libp2p QUIC transport layer lacks proper event handlers for protocol negotiation events that occur after the QUIC handshake is complete. 2. Certificate Validation MismatchHypothesis: Different certificate validation approaches between implementations cause connection failures. Evidence:
Root Cause: Python libp2p's certificate validation logic is incompatible with Go/Rust certificate handling. 3. QUIC Stream Multiplexing IssuesHypothesis: Python libp2p's QUIC stream handling is incompatible with Go/Rust stream multiplexing approaches. Evidence: "No CRYPTO frame found in datagram!" errors suggest QUIC stream processing issues. Root Cause: Different approaches to QUIC stream creation and management between implementations. 4. Connection State ManagementHypothesis: Python libp2p's connection state tracking conflicts with Go/Rust connection lifecycle management. Evidence: "Connection already started" errors indicate duplicate connection attempts. Root Cause: Different connection state machines between implementations. Comparison with Working ImplementationsJava/JVM Success Pattern// JVM treats QUIC as a secure transport
if (params.transport == QUIC_V1) {
it.secureTransports.add(QuicTransport::ECDSA)
} else {
it.transports.add(::TcpTransport)
} Key Insight: Java/JVM implementations treat QUIC as a complete secure transport with built-in security and multiplexing, not as a regular transport requiring additional layers. Python Implementation Pattern# Python libp2p QUIC implementation
if enable_quic:
self.host = new_host(
key_pair=key_pair,
muxer_opt=muxer_options, # QUIC has built-in multiplexing
listen_addrs=[listen_addr],
enable_quic=enable_quic,
quic_transport_opt=quic_config
) Key Insight: Python libp2p treats QUIC as a complete secure transport with built-in security and multiplexing (QUICConnection implements both IRawConnection and IMuxedConn), similar to Java/JVM implementations. The interoperability issue is in protocol negotiation event handling, not architecture. QUIC Interoperability RoadmapCurrent Status: Partial QUIC Interoperability
Required Fixes for Full QUIC Interoperability1. Protocol Negotiation Event Handling
2. Certificate Validation Compatibility
3. Connection State Management
4. QUIC Stream Processing
ConclusionThe test results reveal partial QUIC interoperability for Python libp2p. While Python successfully interoperates with Java/JVM implementations and works as a dialer with Go implementations, it fails when acting as a listener for Go/Rust dialers. Path to Full QUIC Interoperability: The identified issues (protocol negotiation events, certificate validation, connection state management, and QUIC stream processing) need to be addressed in Python libp2p's QUIC implementation to achieve complete cross-implementation QUIC interoperability. |
Beta Was this translation helpful? Give feedback.
-
Appreciate for the report, I will be taking notes from this, in the mean time can you also share the source code for these test runs. Also, we have included a echo interop test using QUIC between py-libp2p and nim-libp2p already, which you can use to get better understanding for what might be actually causing the interop issue. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Dear Py-libp2p team members,
Following the initial review and interoperability testing phase, I’d like to outline the next phase of the QUIC implementation and development work. This phase will be key to strengthening our Python-based QUIC transport for libp2p and aligning it better with broader ecosystem efforts.
After completing the MVP and interoperability testing, our focus should be on implementing QUIC more robustly by leveraging one of the following lower-level approaches:
Depending on your preference and what you find easier to work with, we can decide the exact pathway — all three options are valid and have their own trade-offs in terms of performance, maintenance, and compatibility.
Additionally, it’s worth keeping an eye on some related efforts across the libp2p ecosystem, which could significantly inform and refine our own design:
zig-msquic + zig-libp2p:
There’s work happening to wrap
ms-quic
using Zig’s FFI capabilities for use within Zig-libp2p: please visit https://github.com/MarcoPolo/zig-libp2p➔ This could offer valuable insights into performance optimization and interoperability techniques, and potentially inspire native bindings strategies for Python.
➔ Aleksey (@flcl42) is also exploring MSQUIC integration in
dotnet-libp2p
, providing another parallel track we can learn from: please visit https://github.com/NethermindEth/dotnet-libp2p/tree/main and Quic on Windows should use OpenSSL version NethermindEth/dotnet-libp2p#45Cayman’s js-libp2p-quic (Rust-backed for JS stack):
Cayman (@wemeetagain) has built a Rust-based QUIC transport for
js-libp2p
: please visit https://github.com/ChainSafe/js-libp2p-quic➔ This can be very useful to validate handshake compatibility and muxing behavior across different runtimes, which will become crucial once we do transport interop with
js-libp2p
.➔ Great work by Cayman that we can learn from as we aim for smooth cross-language interoperability.
Waku team's ngtcp2 bindings in Nim:
Our collaborators at Waku are wrapping
ngtcp2
(another QUIC implementation) in Nim using OpenSSL.➔ See here: Waku Nim-libp2p QUIC Transport
➔ Their approach will be a wonderful reference, especially if we consider evaluating other QUIC backend libraries for our use cases or future interop scenarios.
➔ Hats off to @richard-ramos and @vladopajic for their great work here.
Immediate next steps for you:
Beta Was this translation helpful? Give feedback.
All reactions