Wire Protocol
Tubo uses a simple binary framing protocol over libp2p streams. This document describes the frame format, message types, streaming body model, and version negotiation.
Protocol IDs
Tubo registers one libp2p protocol ID:
/p2p-tunnel/1.1— current version, with hello handshake and capability negotiation.
Clients (edge/bridge) negotiate 1.1 only. Legacy /p2p-tunnel/1.0 peers are no longer supported.
Frame format
Each frame on the wire is:
+----------+--------+-----------+ | type (1) | len (varint) | payload | +----------+--------+-----------+
- type — 1 byte, see table below.
- len — unsigned varint (protobuf-style), length of payload in bytes.
- payload — frame-type-specific bytes.
Frame types
| Type byte | Name | Direction | Description |
|---|---|---|---|
0x01 | Hello | Client → Service | Protocol version, role, capabilities (v1.1 only) |
0x02 | RequestHeader | Client → Service | HTTP method, path, headers, connect proof |
0x03 | ResponseHeader | Service → Client | HTTP status code and response headers |
0x04 | BodyChunk | Both | Streaming body data; empty chunk signals end-of-body |
0x05 | Error | Both | Error message; terminates the stream |
Request / Response flow
BodyChunk
to signal end-of-request. Omitting it will cause the service to hang waiting for more data.
Connect proof (v1.1)
In protocol 1.1, the RequestHeader carries a connect proof (PoP) that the service
validates before forwarding the request. The proof binds:
- cluster/namespace/service scope
- access lease hash
- nonce (anti-replay)
- issued-at timestamp
The proof is an Ed25519 signature over the above fields using the client's key.
Version negotiation
libp2p multistream-select handles protocol negotiation. The client proposes
/p2p-tunnel/1.1 and the service must support it.
Tubo 0.10.0 uses /p2p-tunnel/1.1 only. Legacy nodes that only speak
/p2p-tunnel/1.0 are no longer supported.
Discovery protocol
In collaborative namespaces, service announcements are published on a secret-backed Discovery V3 GossipSub topic derived from the namespace discovery entry. The topic string is still opaque, but overlay reachability alone is not enough to discover services in that namespace. Each announcement is JSON-encoded and Ed25519-signed. Subscribers validate the authority-bound publication chain before admitting an entry into the discovery cache.