Skip to content

Feat/multi transport support#1357

Merged
seetadev merged 33 commits into
libp2p:mainfrom
sumanjeet0012:feat/multi_transport_support
Jul 1, 2026
Merged

Feat/multi transport support#1357
seetadev merged 33 commits into
libp2p:mainfrom
sumanjeet0012:feat/multi_transport_support

Conversation

@sumanjeet0012

@sumanjeet0012 sumanjeet0012 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Closes #1359

Description

This PR introduces multi-transport support, bringing py-libp2p closer to go-libp2p's TransportManager architecture. A node can now listen and dial over TCP, WebSocket, and QUIC simultaneously.

Key Features & Changes

  • Multi-Transport Support: You can now pass an explicit transports=[...] list to new_swarm or new_host, or allow transports to be automatically detected from listen_addrs.
  • Transport Manager: Introduced a robust TransportManager to route dials and listens to the correct transport seamlessly.
  • Shared Socket Demultiplexing: PortDemultiplexer allows multiple transports (e.g., TCP and WebSockets) to securely share the same underlying OS port by inspecting incoming byte streams.
  • Robust Exception Handling: Enhanced exception propagation across multiplexers and transports, ensuring trio.Cancelled and KeyboardInterrupt events aren't swallowed.

Breaking Changes ⚠️

  • Removed transport_registry: The libp2p.transport.transport_registry module has been completely removed. Transports should now be explicitly registered via TransportManager or passed as a list to the swarm.
  • Removed legacy transport= keyword: The Swarm.__init__ transport= argument is gone. Attempting to pass a single transport via this keyword will now actively raise a TypeError explaining how to migrate to transports=[...].

Documentation

  • Added a migration guide and updated documentation under docs/examples.multi_transport.rst.
  • Included a 1359.breaking.rst newsfragment to officially document the transport= keyword removal and registry deprecation.

Implements go-libp2p-style multi-transport architecture so a single Host
can listen on and dial over TCP, WebSocket, and QUIC at the same time.

Core changes
------------
* libp2p/abc.py         — Extended ITransport: add can_dial(), can_listen(),
                          protocols() to the interface.
* libp2p/transport/manager.py (NEW)
                        — TransportManager: two-step routing via protocol-name
                          pre-filter + can_dial/can_listen; robust getattr
                          fallbacks for test fakes.
* libp2p/network/swarm.py
                        — Swarm.__init__ now accepts transports: list[ITransport];
                          listen() and _dial_addr_single_attempt() route via
                          TransportManager; QUIC inbound handled via
                          isinstance(rwc, IMuxedConn) not a class check;
                          deprecated swarm.transport property retained.
* libp2p/__init__.py    — new_swarm() / new_host() auto-detect required
                          transports from listen_addrs via transport registry
                          (module-level import for monkeypatch compat);
                          explicit transports= list is highest priority;
                          quic_class= passed at call-site so tests can patch
                          libp2p.QUICTransport.
* libp2p/transport/tcp/tcp.py        — Add can_dial, can_listen, protocols
* libp2p/transport/websocket/transport.py
                                      — can_dial sync (remove spurious await),
                                        add can_listen, protocols
* libp2p/transport/quic/transport.py — Add can_listen, protocols returns list[str]

Tests
-----
* tests/core/transport/test_transport_manager.py (NEW) — 26 unit tests
* Full regression: 529 passed, 2 skipped, 0 failed

Documentation / examples
-------------------------
* examples/multi_transport/server.py — listen on all three simultaneously
* examples/multi_transport/client.py — auto-selects transport from multiaddr
* docs/examples.multi_transport.rst  — API reference + migration guide
* docs/examples.rst                  — added to toctree
* newsfragments/1345.feature.rst
* README.md                          — Multi-Transport section under Transports
- Refactored TransportManager to handle multi-port CMUX shared port bindings
- Fixed interface contract violations in Swarm.py listener handling
- Deprecated TransportRegistry in favor of TransportManager single-source-of-truth
- Resolved PeekableStream/PortDemultiplexer race conditions using proper close callbacks
- Implemented Happy Eyeballs dial routing for Swarm.dial_peer
- Implemented correct listen_order priority sorting in TransportManager.add_transport
- Automatically register CircuitV2Transport in Swarm creation when relay is enabled
@acul71

acul71 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Issue # ?

@sumanjeet0012 sumanjeet0012 force-pushed the feat/multi_transport_support branch from ec8cde6 to aaa41d7 Compare June 29, 2026 18:25
@sumanjeet0012 sumanjeet0012 marked this pull request as ready for review June 30, 2026 16:45
- Prevent event loop blocking in client.py by replacing time.sleep with trio.sleep.
- Refactor _start_one in swarm.py to remove duplicated closure logic and use _handle_inbound_connection.
- Fix type hint drift in DemultiplexedListener and demultiplexed_listen in cmux.py.
…host dead code

- Swarm.__init__ now gracefully handles legacy 'transport=' keyword by throwing a clear TypeError
- Removed unnecessary ValueError raising when instantiating Swarm without transports
- Removed unreachable dead code regarding legacy transport negotiation in basic_host
- Added newsfragment to explicitly document the intentional removal of the transport_registry and legacy transport argument
@acul71

acul71 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Hi @sumanjeet0012 Thanks for this PR and multi transport support. This was and old TODO.
I've seen that you removed transport registry (that I wrote) in favor of transport manager. That's OK.
There is some doc info to fix, and other minor fixes and then it's ready to be merged ?

FULL REVIEW:

AI PR Review: #1357 — Feat/multi transport support

PR: #1357
Author: sumanjeet0012
Reviewed branch: feat/multi_transport_support @ 8ec7110e
Reviewer: AI-assisted review (local validation on 2026-07-01)


1. Summary of Changes

This PR is a feature enhancement that closes issue #1359. It enables a single Swarm / Host to listen on and dial over multiple transports simultaneously (TCP, WebSocket, QUIC), aligning py-libp2p with go-libp2p's TransportManager architecture.

Problem addressed (#1359)

Previously, Swarm accepted only one ITransport. Nodes could not listen on TCP and WebSocket (or QUIC) at the same time, limiting interoperability and NAT traversal.

Core changes

Area Files What changed
Transport routing libp2p/transport/manager.py (new), libp2p/transport/cmux.py (new), libp2p/io/peekable_stream.py (new) TransportManager routes dial/listen by multiaddr; PortDemultiplexer shares a TCP port between plain TCP and WebSocket via 3-byte connection classification
Swarm libp2p/network/swarm.py Accepts transports: list[ITransport] and optional pre-built TransportManager; routes dials/listens through the manager; Happy Eyeballs parallel dialing
Public API libp2p/__init__.py new_swarm() / new_host() gain transports= and auto-detect transports from listen_addrs
Interface libp2p/abc.py ITransport extended with can_dial(), can_listen(), protocols()
Transports tcp.py, websocket/transport.py, quic/transport.py, webrtc/*, relay/circuit_v2/transport.py Implement new routing methods
Removal libp2p/transport/transport_registry.py, tests/core/transport/test_transport_registry.py, docs/examples.transport.rst, several legacy examples Registry-based single-transport selection removed
Tests tests/core/transport/test_transport_manager.py, tests/transport/test_simultaneous_transports.py, tests/transport/test_multi_port_demux.py New unit and integration coverage
Examples / docs examples/multi_transport/*, docs/examples.multi_transport.rst New multi-transport demo; thin Sphinx automodule page

Breaking changes / deprecations

  • libp2p.transport.transport_registry module removed.
  • Swarm(transport=...) keyword raises TypeError (not a deprecation warning).
  • Positional single-transport Swarm(..., tcp_transport) still works silently (no warning).
  • The deprecated swarm.transport property mentioned in early commits does not appear to be present on the current branch.

Maintainer feedback status

@acul71 commented "Issue # ?" on 2026-06-28. The PR body now includes Closes #1359, but there is no author reply to the maintainer comment. Per project merge requirements, maintainer questions should be answered before merge.


2. Branch Sync Status and Merge Conflicts

Branch Sync Status

  • Status: ℹ️ Ahead of origin/main (not behind)
  • Details: 0 31 — branch is 0 commits behind and 31 commits ahead of origin/main

Merge Conflict Analysis

No merge conflicts detected. Test merge against origin/main completed with "Already up to date."


3. Strengths

  • Sound architecture: TransportManager closely mirrors go-libp2p's TransportForDialing / TransportForListening pattern, with protocol-name pre-filtering before can_dial / can_listen checks.
  • Port sharing: PortDemultiplexer + PeekableStream implement go-libp2p-style TCP/WS demux on a shared port, preventing EADDRINUSE when both transports listen on the same TCP port.
  • IPv6 fix: TransportManager.add_listen_addr correctly handles both ip4 and ip6 protocol components instead of unconditionally calling value_for_protocol("ip4").
  • Happy Eyeballs dialing: Swarm.dial_peer parallelizes dials across addresses with a 250 ms stagger, improving multi-address connectivity.
  • Strong test additions: 312-line test_transport_manager.py with stub transports, plus integration tests for simultaneous TCP/WS/QUIC binding and multi-port demux.
  • Interface compliance: All in-tree transports implement the new ITransport routing methods.
  • Local validation passes: make lint, make typecheck, make test, and make linux-docs all succeed on the reviewed branch.

4. Issues Found

Critical

None identified. The full test suite passes locally (3057 tests) and the core routing logic is well-covered.

Major

  • File: newsfragments/1359.feature.rst vs newsfragments/1360.breaking.rst vs libp2p/network/swarm.py
  • Line(s): newsfragments 1–6; swarm 140–143
  • Issue: Contradictory backward-compatibility documentation. The feature newsfragment and PR description state the legacy transport= keyword "still works but emits a DeprecationWarning." The breaking newsfragment and actual code raise TypeError for transport=. Users and release notes cannot both be true.
  • Suggestion: Pick one migration story and align PR body, newsfragments, and code. If the intentional decision is breaking removal (as 1360.breaking.rst states), update 1359.feature.rst and the PR description to remove the deprecation-warning claim. If gradual migration is desired, emit DeprecationWarning instead of TypeError for one release cycle.

newsfragments/1359.feature.rst — lines 5–6

be auto-detected from ``listen_addrs``.  The legacy single-transport
``transport=`` keyword still works but emits a ``DeprecationWarning``.

libp2p/network/swarm.py — lines 140–143

        if kwargs.pop("transport", None):
            raise TypeError(
                "Swarm() no longer accepts 'transport='. Use transports=[...] instead."
            )

  • File: newsfragments/1360.breaking.rst
  • Line(s): 1
  • Issue: Invalid newsfragment issue number. The file is named 1360.breaking.rst, but issue #1360 does not exist. Towncrier requires newsfragments to use real issue numbers. This is a merge blocker under project policy.
  • Suggestion: Either open issue #1360 (or another issue) describing the breaking removal of transport_registry / transport= and reference it in the PR, or fold the breaking-change note into 1359.feature.rst / a 1359.breaking.rst if the breakage is considered part of the same enhancement issue.

  • File: GitHub PR discussion
  • Line(s): N/A
  • Issue: Maintainer question unanswered. @acul71 asked "Issue # ?" before the PR body was updated with Closes #1359. No reply is visible in the thread.
  • Suggestion: Reply to @acul71 confirming Enhancement: Multi transport capability #1359 is the tracking issue and summarize scope. Maintainers (pacrob, acul71, seetadev) must have their feedback addressed before merge.

  • File: docs/examples.multi_transport.rst, PR description To-Do
  • Line(s): docs file (all); PR body To-Do section
  • Issue: Documentation incomplete relative to PR goals. The new ReST page is only automodule stubs with no migration guide, API overview, or usage narrative. The PR still has unchecked To-Do items ("Clean up commit history", "Add or update documentation", "Add entry to release notes"). The older docs/examples.transport.rst and examples/transport/transport_integration_demo.py were removed without a user-facing migration note in the docs tree (only the thin automodule page remains).
  • Suggestion: Add a short migration section to docs/examples.multi_transport.rst (or getting_started.rst) covering: transports=[...] API, auto-detection from listen_addrs, removal of transport_registry, and the transport=transports= change. Mark PR To-Do items done or explain deferrals.

  • File: libp2p/transport/manager.py
  • Line(s): 159–160, 198–199
  • Issue: Permissive routing fallback. When a registered transport lacks can_dial / can_listen, the manager treats it as capable (if _can_dial is None or _can_dial(maddr)). This was added for test fakes, but it violates the now-abstract ITransport contract and could misroute if a third-party transport forgets to implement the methods (Python ABC does not prevent instantiation of incomplete subclasses in all cases).
  • Suggestion: Remove the None fallback for production transports, or log a warning when falling back. Keep stub behavior scoped to tests only.

libp2p/transport/manager.py — lines 159–161

            _can_dial = getattr(transport, "can_dial", None)
            if _can_dial is None or _can_dial(maddr):
                logger.debug(

  • File: tests/core/network/test_swarm.py (missing test)
  • Line(s): N/A
  • Issue: No test for Swarm(transport=...) TypeError or positional backward compat. The breaking transport= behavior and silent positional single-transport path are untested, despite being user-visible API changes.
  • Suggestion: Add tests asserting pytest.raises(TypeError) for Swarm(..., transport=TCP()) and successful construction for Swarm(..., transports=[TCP()]) and positional Swarm(..., TCP()).

Minor

  • File: libp2p/transport/manager.py

  • Line(s): 345–350, 371–376

  • Issue: Accesses private PortDemultiplexer attributes (_send_channels, _listeners) for idempotent listener registration.

  • Suggestion: Expose a small public has_listener(conn_type) / get_listener(conn_type) API on PortDemultiplexer.

  • File: libp2p/transport/cmux.py

  • Line(s): 176–179

  • Issue: _drain() catches BaseException with a bare pass, which can mask trio.Cancelled propagation during shutdown.

  • Suggestion: Re-raise trio.Cancelled / KeyboardInterrupt; only swallow expected handler errors.

libp2p/transport/cmux.py — lines 176–179

            except Exception:
                pass
            except BaseException:
                pass
  • File: PR commit history

  • Line(s): N/A

  • Issue: 31 commits with merge commits and iterative fixups; author To-Do includes "Clean up commit history."

  • Suggestion: Squash or rebase into a smaller set of logical commits before merge (project preference; not a functional blocker).

  • File: libp2p/transport/cmux.py

  • Line(s): 185

  • Issue: DemultiplexedListener.listen falls back to trio.lowlevel.spawn_system_task when background_nursery is unset, which can outlive the Swarm lifecycle.

  • Suggestion: Require background_nursery (Swarm already waits for it before listening) and remove the fallback, or document when the fallback is safe.


5. Security Review

  • Risk: Connection-type misclassification on shared TCP port (3-byte peek).

  • Impact: Low

  • Mitigation: Unknown prefixes are not routed to any listener and connections are dropped after timeout. Matches go-libp2p behavior. Monitor for protocol confusion attacks only if new conn types are added without updating classifiers.

  • Risk: Permissive can_dial is None routing fallback (see Major issue).

  • Impact: Low (only affects misconfigured custom transports).

  • Mitigation: Enforce ITransport method implementation; remove silent fallback.

  • Risk: WebSocket upgrade errors logged with exc_info=True on shared port.

  • Impact: Low

  • Mitigation: Acceptable for debugging; ensure no sensitive handshake material is logged at ERROR level in production configs.

No authentication bypass, key handling, or input-validation regressions identified in the transport routing layer.


6. Documentation and Examples

Item Status
examples/multi_transport/server.py and client.py ✅ Present; demonstrate TCP + WS + QUIC on same port
docs/examples.multi_transport.rst ⚠️ Automodule stubs only — no migration guide or narrative
docs/examples.transport.rst ❌ Removed
README.md multi-transport section ❌ Not in current diff (mentioned in early commit, absent from final file list)
new_swarm / new_host docstrings ✅ Updated with priority order and examples
PR To-Do documentation items ❌ Still unchecked

The examples are useful, but user-facing documentation does not yet explain the breaking removal of transport_registry or the transport= keyword change.


7. Newsfragment Requirement

File Issue ref Valid? Notes
newsfragments/1359.feature.rst #1359 ⚠️ Partially Content contradicts actual transport= behavior
newsfragments/1360.breaking.rst #1360 ❌ Blocker Issue #1360 does not exist

Action required before approval:

  1. Resolve the contradiction between 1359.feature.rst (deprecation warning) and code/1360.breaking.rst (hard removal).
  2. Fix or replace 1360.breaking.rst with a newsfragment tied to a real issue number.
  3. Ensure every user-visible breaking change has accurate, non-conflicting release notes.

8. Tests and Validation

Linting (make lint)

  • Exit code: 0 (passed)
  • Result: All pre-commit hooks passed (ruff, ruff format, mdformat, mypy, pyrefly, path audit).
  • Issues: None

Type checking (make typecheck)

  • Exit code: 0 (passed)
  • Result: mypy and pyrefly both passed.
  • Issues: None

Test execution (make test)

  • Exit code: 0 (passed)
  • Summary: 3057 passed, 16 skipped, 2 warnings in 158.65s
  • Skipped: 16 tests (pre-existing skips, e.g. test_is_closed_skipped)
  • Warnings (2): RuntimeWarning: coroutine 'AsyncMockMixin._execute_mock_call' was never awaited in tests/core/transport/webrtc/test_connection.py — pre-existing WebRTC mock issue, unrelated to this PR
  • New tests exercised successfully: test_transport_manager.py, test_simultaneous_transports.py, test_multi_port_demux.py

Documentation build (make linux-docs)

  • Exit code: 0 (passed)
  • Result: Sphinx built 107 sources with -W (warnings as errors); no build failures
  • Note: examples.multi_transport page generated from automodule directives

9. Peerstore & Multi-Transport Integration

Peerstore was already transport-agnostic (a flat Multiaddr addr-book per peer with TTLs, plus proto/key/metrics books). This PR does not change the peerstore data model — and that is the correct libp2p design. What changes is how the host and swarm populate, advertise, and dial addresses across multiple transports.

Peerstore — handled well

Flow Behavior in multi-transport scenario Assessment
Inbound learning After connect, Identify's _update_peerstore_from_identify() adds every remote listen_addr (TCP, WS, QUIC, etc.) with a 2-hour TTL ✅ Correct
Outbound dialing connect() merges peer_info.addrs into peerstore, then dial_peer() reads peerstore.addrs(peer_id) and Happy Eyeballs dials up to 8 addresses in parallel; each addr is routed by TransportManager.transport_for_dialing() ✅ Correct
Self advertisement BasicHost.get_transport_addrs() iterates all swarm.listeners and merges with observed (NAT) addresses in get_addrs(); Identify sends the full set as listen_addrs ✅ Correct
Test coverage test_host_connect updated to assert host 0 learns all of host 1's advertised addresses, not just one ✅ Improved

Peerstore does not record which transports the local host supports. That is intentional: it caches remote reachability. If peerstore holds a QUIC addr but the local host only registered TCP, dials to that addr fail (logged) until TTL expires — harmless when another addr (e.g. TCP) succeeds via Happy Eyeballs.

Observed addresses / NAT — transport-aware

ObservedAddrManager is well-suited to multi-transport:

  • Splits addresses into a thin waist (/ip4/…/tcp/… or /ip4/…/udp/…) and matches observations per transport family.
  • Rest suffix inference (/ws, /quic-v1, etc.) is derived from local listen addresses passed via get_transport_addrs().
  • get_nat_type() returns separate TCP and UDP NAT classifications.

Identify passes the full transport address list into record_observation(), so all listen paths participate in NAT discovery.

Swarm connections — multi-path per peer

  • connections[peer_id] is a list (default max_connections_per_peer = 3), so a node can hold TCP and QUIC connections to the same peer simultaneously.
  • Happy Eyeballs may open multiple connections until the per-peer limit; older connections are trimmed.
  • dial_peer() reuses any existing open connection without preferring transport type — usually fine, but means a TCP conn may be reused even when a QUIC addr is also available.

Other subsystems — unchanged model, per-address evaluation

Subsystem Multi-transport impact
Signed peer records Transport-independent; records may contain multiple addrs across protocols
Connection gate / rcmgr Evaluated per multiaddr (IP extracted per dial/listen attempt)
Circuit relay v2 Reads peerstore addrs and filters /p2p-circuit paths — unaffected
Protocol book (proto book) Independent of transport layer

Gaps and watch items

Area Status Notes
Filter peerstore addrs by local transport capability before dial ❌ Not implemented Dial-and-fail is acceptable when another addr works; may add latency/noise in logs
Transport-aware connection reuse ❌ Not implemented First open connection wins regardless of transport
Identify + peerstore with simultaneous TCP/WS/QUIC hosts ⚠️ Limited tests test_simultaneous_transports.py covers binding/dialing; no test that Identify populates peerstore with all three addr families from one remote
enable_webrtc without WebRTC listen addrs ❌ Dead parameter on PR branch Interop still works because it passes /webrtc-direct in listen_addrs

Registry removal vs peerstore (supplementary)

The removed transport_registry was a local transport factory for new_swarm(), not a peerstore component. Peerstore was never coupled to it. Auto-detection logic moved into _build_transports_for_swarm(); peerstore interaction paths are unchanged.

Bottom line: Peerstore and the identify/observed-addr pipeline are compatible with multi-transport without structural changes. The PR correctly wires address advertisement and per-address dial routing. Remaining gaps are operational (dialing unsupported addrs, connection reuse policy), not peerstore storage bugs.


10. Recommendations for Improvement

  1. Align backward-compat story: Update PR description, 1359.feature.rst, and code so they agree on whether transport= is deprecated (warning) or removed (TypeError). Consider emitting DeprecationWarning for positional single-transport for one release.
  2. Fix newsfragment #1360: Open a tracking issue for the transport_registry removal or merge breaking notes into Enhancement: Multi transport capability #1359 with 1359.breaking.rst.
  3. Reply to @acul71 confirming issue Enhancement: Multi transport capability #1359 and scope.
  4. Add migration documentation beyond automodule stubs — especially for removed transport_registry and changed Swarm constructor.
  5. Add API regression tests for Swarm(transport=...) TypeError and positional/list transports forms.
  6. Tighten TransportManager routing — drop can_dial is None fallback or warn loudly.
  7. Squash commits before merge per author To-Do and reviewer ergonomics.
  8. Add an Identify + peerstore integration test where a multi-transport host advertises TCP, WS, and QUIC addrs and a connecting peer's peerstore receives all of them after Identify.

11. Questions for the Author

  1. Was the intentional decision to raise TypeError for Swarm(transport=...) rather than emit DeprecationWarning as documented in the PR body and 1359.feature.rst?
  2. Should the breaking removal of transport_registry be tracked under Enhancement: Multi transport capability #1359 or a separate issue? If separate, can you open it so 1360.breaking.rst is valid?
  3. Is shared-port TCP + WebSocket dialing (client connects to /tcp/N while server also has /tcp/N/ws) covered by integration tests beyond listener binding? A cross-transport echo test on the same port would increase confidence.
  4. Why was the swarm.transport deprecated property removed rather than retained as an alias to transport_manager.get_transports()[0]?
  5. Will the commit history be squashed before merge, as noted in the PR To-Do?
  6. Should dial_peer() prefer opening a connection on a specific transport when peerstore holds multiple addr families, or is "first open connection wins" the intended go-libp2p-aligned behavior?

12. Overall Assessment

Metric Rating
Quality Rating Good — solid architectural alignment with go-libp2p, well-tested core routing, clean local CI
Security Impact Low
Merge Readiness Needs fixes — newsfragment validity/contradiction and maintainer reply are blockers; documentation gaps should be addressed
Confidence High — full local test/lint/typecheck/docs run on checked-out branch; code review of transport manager, cmux, and swarm integration

This is a valuable, well-engineered feature that addresses a real gap in py-libp2p. The implementation and test coverage for multi-transport routing are strong. Before merge, the project should resolve the conflicting backward-compat documentation, fix the invalid 1360.breaking.rst newsfragment, respond to maintainer feedback, and flesh out user-facing migration docs.

@acul71

acul71 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Thanks @sumanjeet0012 — reviewed the latest commit (a10f61a7, Fix remaining PR feedback from code review). Nice progress addressing several review items.

Addressed in a10f61a7

  • Newsfragments: removed the incorrect DeprecationWarning claim from 1359.feature.rst; renamed 1360.breaking.rst1359.breaking.rst (valid issue Enhancement: Multi transport capability #1359).
  • TransportManager: can_dial / can_listen no longer treat missing methods as a match.
  • cmux: re-raise Cancelled/KeyboardInterrupt; require background_nursery instead of spawn_system_task; added has_listener() / get_listener().
  • manager.py: uses the new public cmux API instead of private attributes.
  • Tests: Swarm(transport=...) TypeError and positional backward-compat coverage.
  • Docs: short migration guide in docs/examples.multi_transport.rst.

Still open (non-blocking unless noted)

  • Please reply on the thread to @acul71’s “Issue # ?” — confirm Enhancement: Multi transport capability #1359 is the tracking issue (maintainer merge hygiene).
  • enable_webrtc is still accepted by new_host/new_swarm but not wired in new_swarm() (dead parameter; interop works via listen_addrs).
  • Optional: Identify + peerstore test for a multi-transport host (all advertised addrs learned after connect).
  • PR To-Do: commit history cleanup / fuller docs if you plan to do those before merge.

Local spot-check on the new tests passed. Happy to re-review after any follow-up.

@sumanjeet0012

Copy link
Copy Markdown
Contributor Author

@acul71 I have wired enable_webrtc and added tests.

@acul71

acul71 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Thanks @sumanjeet001248053c07 closes the remaining items from the last review round.

Looks good in 48053c07

  • enable_webrtc is now wired through _build_transports_for_swarm() / new_swarm().
  • test_identify_multi_transport_host_addresses covers TCP + WS multi-listen Identify advertisement.

Together with a10f61a7, the major review feedback is addressed (newsfragments, TransportManager routing, cmux lifecycle, Swarm API tests, migration note).

Small nits before merge (non-blocking)

  • Please add a one-line reply confirming Enhancement: Multi transport capability #1359 is the tracking issue (re your earlier “Issue # ?” thread).
  • PR description still mentions a DeprecationWarning for transport= — worth updating to match the current TypeError + 1359.breaking.rst.
  • Optional: squash commit history if you still plan to (PR To-Do).

CI was green on lint/docs/interop; core matrix was still running when I last checked.

Nice work on this — very close from my side once the above hygiene is done.

@sumanjeet0012

Copy link
Copy Markdown
Contributor Author

@acul71 PR description does not mention DeprecationWarning, its already removed.
Rest of the things are already in place.

@seetadev

seetadev commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@sumanjeet0012 , @acul71 : This is an outstanding contribution that significantly advances py-libp2p's networking capabilities.

The multi-transport architecture is well designed, aligns closely with the broader libp2p ecosystem, and introduces a clean, maintainable TransportManager abstraction while simplifying the overall transport layer.

Appreciate the thorough testing, comprehensive documentation updates, and the attention given to backward compatibility and migration guidance.

The implementation is clean, well-structured, and backed by a strong CI matrix, giving confidence in its correctness and long-term maintainability.

Overall, this is a high-quality contribution that closes a long-standing feature gap and provides a solid foundation for future transport enhancements.

@sumanjeet0012 : Excellent work, and thank you for your persistence and collaboration throughout the review process with @acul71.

CCing @mishmosh and @johannamoran

@seetadev

seetadev commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@sumanjeet0012 , @acul71 : Please open a detailed discussion page at py-libp2p on this PR.

Overtime, this will be further scaled up and be made available as spec addition at libp2p.

@seetadev seetadev merged commit 117db86 into libp2p:main Jul 1, 2026
75 checks passed
@acul71 acul71 deleted the feat/multi_transport_support branch July 1, 2026 19:17
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.

Enhancement: Multi transport capability

3 participants