Skip to content

Hole Punching Interop Tests for py-libp2p with other libp2p modules #733

@seetadev

Description

@seetadev

Description

We aim to build an interoperability test suite for the hole punching feature in py-libp2p. Hole punching allows peers behind NATs to establish direct connections using a relay only for coordination, improving connection efficiency and reducing relay load.

The purpose of this test suite is to verify that py-libp2p can correctly perform hole punching with peers using other libp2p implementations, such as go-libp2p and js-libp2p. This includes ensuring that py-libp2p follows the hole punching protocol as specified and behaves reliably in real-world NAT scenarios.

This effort is critical to ensure py-libp2p is fully interoperable with the broader libp2p ecosystem and can be used confidently in production-level P2P applications.

Motivation

Hole punching is a core feature of the libp2p stack that enables direct peer-to-peer connections across NATs, which are extremely common in real-world network environments. Without hole punching, peers often have to rely on relayed connections, which introduce latency, limit bandwidth, and require ongoing relay infrastructure.

While py-libp2p has evolving support for hole punching, it's essential to ensure that its implementation is interoperable with other widely used libp2p implementations, particularly go-libp2p and js-libp2p. These implementations already support hole punching and are used in production systems across IPFS, Filecoin, and other decentralized protocols.

Developing a dedicated interop test suite will help us:

  • Validate that py-libp2p handles the hole punching coordination flow correctly, including relay setup, timing windows, and NAT traversal.
  • Confirm that py-libp2p can both initiate and respond to hole punching attempts from other libp2p nodes.
  • Detect edge cases, bugs, or non-standard behavior early before this feature is promoted for broader use.
  • Build confidence that Python-based libp2p applications can seamlessly join existing P2P networks that rely on NAT traversal.

This is also a stepping stone toward more robust interop testing practices across libp2p implementations, helping ensure long-term protocol health, developer confidence, and deployment readiness.

Requirements

To ensure robust interoperability of hole punching in py-libp2p, the test suite and the underlying feature must satisfy the following functional and testing requirements:

1. Relay-Aware Peer Discovery & Setup

  • The Python peer must be able to discover and connect to a relay node (e.g., a go-libp2p relay with /p2p-circuit support).

  • The relay must support circuit v2 and participate in hole punching coordination according to the libp2p spec.

  • The Python peer must be capable of acting as both:

    • Initiator: Starts the hole punching attempt.
    • Receiver: Waits for an incoming punch attempt.

2. Protocol Compliance

  • Must support the relay v2 protocol and handle all required stream negotiations.

  • Must implement the DCUtR (Direct Connection Upgrade through Relay) protocol flow.

  • Should comply with Hole Punching Spec, including:

    • Observed address exchange
    • Timed simultaneous dial attempts
    • Fallback to relayed connection if punching fails
    • Proper error propagation if NAT traversal is not possible

3. Cross-Implementation Compatibility

  • Must successfully execute hole punching when interacting with:

    • go-libp2p (reference implementation)
    • js-libp2p
    • nim-libp2p
    • dotnet-libp2p
    • zig-libp2p
    • rust-libp2p
    • 🔄 Other Python peers (self-interoperability)
  • Must tolerate slight timing differences and implementation details in protocol behavior across platforms.

4. Test Suite Capabilities

  • Must support running in a single codebase (ideally Python) with Docker/network tooling to simulate NATs and relay environments.

  • Should:

    • Start relays and peers in separate containers or subprocesses.
    • Simulate NAT behavior using tools like iptables, netns, or pumba.
    • Validate that both peers successfully upgrade from a relayed connection to a direct connection.
    • Log connection events, retries, and fallback paths.

5. Connection Verification

  • The test suite must verify:

    • A successful hole punch results in a direct connection, not routed through the relay.
    • The peer connections are upgraded correctly with the same muxer/security.
    • No additional unwanted streams are leaked or left open.
    • Round-trip latency and connection state match expectations.

6. Observability and Logging

  • Must include detailed logs of:

    • Observed address exchange
    • Dial attempts and timestamps
    • Hole punch success/failure
    • Fallbacks and retry behavior
  • Optional: Produce a test report that includes connection topology and timing diagrams.

7. Automation and CI Integration (Nice to Have)

  • Should support automated execution as part of the CI pipeline, ideally triggered by a label or tag.
  • Should test against known good versions of go-libp2p and js-libp2p.
  • Should include setup scripts (e.g., Docker Compose, shell) to launch relay + NAT + peer topology locally or in CI.

Open questions

No response

Are you planning to do it yourself in a pull request ?

Maybe

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions