Skip to content

refactor(webrtc): deduplicate _varint.py — use libp2p.utils.varint #1355

Description

@acul71

Summary

PR #1309 adds libp2p/transport/webrtc/_varint.py with encode_uvarint() and decode_uvarint() for WebRTC data-channel and signaling framing. The same unsigned LEB128 logic already exists in the canonical project module libp2p/utils/varint.py, which is used by mplex, msgio, peer envelopes, identify, interop tests, and others.

This is duplicated code on the same wire format; WebRTC should reuse the shared utility rather than maintain a fourth in-tree varint implementation (alongside libp2p/utils/varint.py, the external varint PyPI package used in kad-dht/bitswap/filecoin, and _varint_size() in pubsub/rpc_queue.py).

Current duplication

WebRTC (_varint.py) Existing (libp2p/utils/varint.py)
encode_uvarint(value) encode_uvarint(value) — same algorithm
decode_uvarint(data, offset=0) -> (value, bytes_consumed) decode_varint_with_size(data) -> (value, bytes_consumed) (no offset; use data[offset:])
decode_uvarint_from_stream(reader) — async stream read

Consumers today:

  • libp2p/transport/webrtc/stream.pyencode_uvarint / decode_uvarint for SCTP message framing
  • libp2p/transport/webrtc/signaling.pyencode_uvarint for writes; custom _read_uvarint() for async reads (duplicates decode_uvarint_from_stream)

The encode loops are functionally identical (while value > 0x7F vs while value >= 0x80 is equivalent). Decode-with-length maps 1:1 to decode_varint_with_size.

Suggested approach

  1. Delete libp2p/transport/webrtc/_varint.py.

  2. Update imports in stream.py and signaling.py:

    from libp2p.utils.varint import (
        encode_uvarint,
        decode_varint_with_size,
        decode_uvarint_from_stream,
    )
  3. Replace decode_uvarint(raw) with decode_varint_with_size(raw) in stream.py (same (value, consumed) tuple).

  4. Replace signaling._read_uvarint() with decode_uvarint_from_stream(stream), mapping ParseError to WebRTCSignalingError at the call site if needed.

  5. Update tests in tests/core/transport/webrtc/test_signaling.py that import from _varint to use libp2p.utils.varint (or test via public signaling/stream APIs only).

No wire-format or protocol change — this is a pure refactor.

Minor API differences to handle

  • Offset parameter: WebRTC decode_uvarint(data, offset) can be replaced by slicing: decode_varint_with_size(data[offset:]), then adjust consumed if callers need absolute offset (currently stream.py uses offset 0 only).
  • Error types: WebRTC raises ValueError on truncated varints; utils uses ParseError in some stream paths and ValueError in others. Preserve existing WebRTC error handling at boundaries if tests depend on it.
  • Empty/truncated input: Confirm edge-case behavior matches (utils decode_varint_with_size on empty bytes returns (0, 0); WebRTC raises ValueError — verify call sites never hit empty prefix, or add explicit checks).

Scope / timing

Acceptance criteria

  • _varint.py removed
  • WebRTC stream and signaling modules import from libp2p.utils.varint
  • All tests/core/transport/webrtc/ tests pass
  • No change to on-wire framing behavior

Refs #546, #1309.

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