Warpnet Protocol
This document describes the peer-to-peer communication layer of Warpnet, including transport channels, routing logic, and delivery semantics. It focuses on how nodes exchange encrypted messages over libp2p.
1. Transport Protocols
Warpnet is built on libp2p. Every connection is authenticated and encrypted with the Noise handshake, and the whole swarm runs as a libp2p private network gated by a pre-shared key. TCP traffic additionally goes through a camouflage transport that makes it look like ordinary HTTPS to Deep Packet Inspection.
The pre-shared key. The PSK is derived deterministically from the network name and the node's major version. A node whose major version differs cannot complete a handshake at all — PSK enforcement happens at connection setup, before any stream is opened, not as a later validation step.
What is a libp2p stream?
A libp2p stream is:
A logical connection, established between two peers on top of an existing libp2p connection
Identified by a protocol ID string, such as /private/post/tweet/0.0.0
Multiplexed: multiple streams can share a single physical connection
Bidirectional: both peers can read and write from/to the stream
Automatically encrypted and authenticated using the Noise protocol + PSK
The initiator opens the stream, the recipient's handler processes it, and it is closed on completion.
Protocol URI format
All Warpnet protocols follow a structured URI-style format that encodes access level, operation type, resource domain, and version.
/{visibility}/{operation}/{domain}[/{subpath}…]/{version}
Where:
visibility — public or private
operation — exactly one of get, post, delete
domain — the logical entity (tweet, message, user, filter, …), optionally followed by one or two sub-path segments for nested operations
version — currently 0.0.0 on every application route
Roughly a third of the routes use the extended form, e.g. /private/post/filter/keyword/update/0.0.0 or /public/get/tweet/reactors/0.0.0.
Note that 0.0.0 is a placeholder, not live version negotiation. Real versioning today lives on the pubsub and DHT layer: /warpnet/discovery/1.0.0, /warpnet/stats/1.0.0, /warpnet/reports/1.0.0, and the DHT rendezvous namespace warpnet/rendezvous/<network>.
Benefits of Structured Protocols
Self-documenting: each protocol clearly communicates its purpose
Modular dispatch: handlers are mapped via URI parsing
Access control: easy to reason about public/private rules by prefix
Versionable: future changes can use semantic versions without breaking older clients
Wire format
The initiator writes a single JSON envelope and then half-closes the write side of the stream; EOF is the frame delimiter. There is no application-level length prefix. The envelope is:
{ "body": { }, "message_id": "…", "node_id": "…", "path": "/private/post/tweet/0.0.0", "timestamp": "…", "version": "0.0.0", "signature": "…" }
The Ed25519 signature covers the raw body concatenated with the timestamp in Unix nanoseconds. Payloads are capped at 50 MiB; an oversized stream is reset.
Middleware
Every registered route — public and private alike — is wrapped in the same chain: logging → authentication → unwrap. Authentication rejects a message that is unparseable, unsigned, signed by a key that does not match the remote peer ID, or whose timestamp drifts more than five minutes from now (replay protection). Loopback self-streams are exempt from the freshness check only.
Requests on /post/ routes additionally pass an idempotency cache keyed by protocol, peer ID and message ID (10-minute TTL). A retried request returns the original response instead of re-running the side effect, and concurrent duplicates collapse into a single handler invocation.
2. Message Routing
Routing depends on the operation, not on a single broadcast route.
Timeline fan-out is gossip, not a stream. When a member publishes a tweet, the node publishes it to the gossipsub topic user-update-<ownerID>. Followers subscribe to that topic when they follow and unsubscribe when they unfollow. The envelope's path field carries /private/post/tweet/0.0.0 so the receiver can dispatch it locally. There is no /public/post/timeline/… route.
Direct messages dial the recipient. Creating a conversation streams to the peer over /public/post/chat/0.0.0; sending a message streams over /public/post/message/0.0.0. The /private/get/chat/0.0.0 and /private/get/messages/0.0.0 routes are local reads against the node's own store, not network calls.
Node roles. A member node carries the full application surface — 81 routes. A relay node serves only /public/get/info/0.0.0 and provides circuit relay and hole punching. A moderator node serves that route plus the moderator-to-moderator audit route /public/get/moderate/challenge/0.0.0.
Local UI uses the same protocol. The desktop and Android clients do not speak a separate API. They dispatch the same protocol IDs over an in-memory loopback stream, so a local read and a remote read take identical paths.
3. Delivery Semantics
Warpnet is best-effort and eventually consistent — but several reliability primitives are now part of the protocol rather than left to the application.
Every message carries a ULID message ID and a UTC timestamp.
Stream sends retry within a bounded budget; a peer that is provably unreachable short-circuits instead of retrying.
Messages for an offline peer are persisted in an outbox and re-sent when the peer reappears. GET routes are never queued.
Duplicates are absorbed by the idempotency cache described above, so a retry is safe by construction.
Timeline merge stays deterministic per node, ordered by user ID and timestamp.
There is still no global queue and no delivery receipt across the whole network.
4. Registered Routes
81 routes are registered on a member node. Relay nodes serve /public/get/info/0.0.0 only; moderator nodes serve that plus /public/get/moderate/challenge/0.0.0.
Admin & node (5)
/private/post/admin/pair/0.0.0 /private/get/admin/stats/0.0.0 /public/get/info/0.0.0 /public/post/moderate/result/0.0.0 /public/post/report/0.0.0
Tweets (12)
/private/get/timeline/0.0.0 /private/post/tweet/0.0.0 /private/post/tweet/edit/0.0.0 /private/delete/tweet/0.0.0 /private/post/import/twitter/tweet/0.0.0 /public/get/tweet/0.0.0 /public/get/tweets/0.0.0 /public/get/tweetstats/0.0.0 /public/post/retweet/0.0.0 /public/post/unretweet/0.0.0 /public/post/pin/0.0.0 /public/post/unpin/0.0.0
Engagement (8)
/private/get/reactions/0.0.0 /public/post/react/0.0.0 /public/post/unreact/0.0.0 /public/post/view/0.0.0 /public/get/tweet/reactors/0.0.0 /public/get/tweet/retweeters/0.0.0 /public/get/poll/0.0.0 /public/post/poll/vote/0.0.0
Follows (6)
/public/post/follow/0.0.0 /public/post/unfollow/0.0.0 /public/post/isfollowing/0.0.0 /public/post/isfollower/0.0.0 /public/get/followers/0.0.0 /public/get/followings/0.0.0
Follow requests (3)
/private/get/follow/requests/0.0.0 /private/post/follow/request/authorize/0.0.0 /private/post/follow/request/reject/0.0.0
Content filters (8)
/private/get/filter/0.0.0 /private/get/filters/0.0.0 /private/post/filter/0.0.0 /private/post/filter/update/0.0.0 /private/delete/filter/0.0.0 /private/post/filter/keyword/0.0.0 /private/post/filter/keyword/update/0.0.0 /private/delete/filter/keyword/0.0.0
Settings (4)
/private/get/notification/settings/0.0.0 /private/post/notification/settings/0.0.0 /private/get/gateway/settings/0.0.0 /private/post/gateway/settings/0.0.0
Users (7)
/public/get/user/0.0.0 /public/get/users/0.0.0 /public/get/users/search/0.0.0 /public/get/whotofollow/0.0.0 /private/post/user/0.0.0 /private/post/subscribe/user/0.0.0 /private/post/unsubscribe/user/0.0.0
Chats & messages (8)
/public/post/chat/0.0.0 /public/post/message/0.0.0 /private/get/chat/0.0.0 /private/get/chats/0.0.0 /private/delete/chat/0.0.0 /private/get/message/0.0.0 /private/get/messages/0.0.0 /private/delete/message/0.0.0
Media (6)
/private/post/image/0.0.0 /public/get/image/0.0.0 /private/post/video/0.0.0 /public/get/video/0.0.0 /private/post/media/meta/0.0.0 /private/get/media/0.0.0
Notifications (5)
/private/get/notification/0.0.0 /private/get/notifications/0.0.0 /private/get/pushes/0.0.0 /private/post/notification/read/0.0.0 /private/post/notifications/read/0.0.0
Blocks & mutes (6)
/private/post/block/0.0.0 /private/post/unblock/0.0.0 /private/get/blocks/0.0.0 /private/post/mute/0.0.0 /private/post/unmute/0.0.0 /private/get/mutes/0.0.0
Bookmarks (3)
/private/post/bookmark/0.0.0 /private/post/unbookmark/0.0.0 /private/get/bookmarks/0.0.0
Moderator-only
/public/get/moderate/challenge/0.0.0
Not libp2p routes. /private/post/login/0.0.0 and /private/post/logout/0.0.0 are handled by the local client/WebSocket layer before the node is up; they never travel over the network. /public/post/admin/challenge/0.0.0 is a legacy constant with no handler registered anywhere.
Pubsub topics
/warpnet/discovery/1.0.0 peer discovery /warpnet/stats/1.0.0 CRDT-replicated counters /warpnet/reports/1.0.0 moderation reports /warpnet/moderation/votes/1.0.0 moderator ballots user-update-<ownerID> per-author timeline fan-out
Warpnet Peer Discovery
The discovery service finds peers, connects to them, validates them, and — for real users — pulls their profile into the local store. Four sources feed it, plus the DHT bootstrap seed.
There is no single HandlePeerFound entry point. Each backend has its own handler — DiscoveryHandlerMDNS, DiscoveryHandlerDHT, DiscoveryHandlerStream, DiscoveryHandlerPubSub — and all four funnel into one internal queue. Processing is asynchronous: a worker goroutine drains the queue and branches on the node's own role (member, relay, or moderator).
Discovery pipeline (member node)
Drop empty peer IDs and our own ID.
Rate limit — a leaky bucket, capacity 32, draining 2 per 10 seconds.
Enqueue into a 128-slot buffer. On overflow, a jittered batch of the oldest entries is dropped.
Blocklist check. Blocked peers are marked offline and dropped.
Connect. Noise + PSK is enforced here; a dial under backoff is skipped.
Alias-cache check. If this peer is already known under another ID, raise its priority and stop.
Request NodeInfo over /public/get/info/0.0.0.
Record the peer's aliases and set its connection priority from its reported reachability.
Stop early for relays, the Mastodon gateway, and moderators — none of them get a user sync.
Deduplicate against the local database by node ID.
Request the owner's profile over /public/get/user/0.0.0, measuring round-trip time.
Create the user locally, or update the existing record.
Discovery backends
1. PubSub — the primary source. A dedicated gossipsub topic, /warpnet/discovery/1.0.0. Members listen for relay announcements; relays listen for member announcements.
2. mDNS — LAN discovery via multicast announcements, for peers on the same local network. Member nodes only.
3. DHT — a Kademlia DHT under the network-scoped protocol prefix, plus rendezvous: the node advertises itself as a provider for warpnet/rendezvous/<network> and queries the same namespace for others.
4. Stream — reciprocal. When a remote peer asks us for /public/get/info/0.0.0, we feed that peer back into discovery. Peers whose addresses are already in the peerstore are filtered out so the loop terminates.
5. Bootstrap seed — bootstrap addresses are inserted into the peerstore with a permanent TTL before the DHT bootstraps.
Bootstrap peer handling
Bootstrap (relay) nodes are registered as static relay candidates for AutoRelay, pinned at maximum connection priority, and inserted into the DHT routing layer. They are never user-synced. If a bootstrap address answers under a different peer ID than configured, the mismatch is detected and the peerstore entry is corrected automatically.
Blocklist
Misbehaving peers escalate through 1 hour → 24 hours → 7 days → permanent. A user-initiated block goes straight to permanent and is reversible by unblocking.
Summary
Discovery is multi-source but single-queued
Only peers that share the PSK can connect at all
Each connected peer is asked for its node info; real member peers are asked for their owner profile exactly once per node ID
Self, duplicates, blocklisted peers, aliases, relays, moderators and the gateway are all filtered out along the way
WarpNet discovery is designed for resilience, modularity, and zero-trust-by-default peer authentication.
Contacts
© 2026. All rights reserved. Legal information.
Donation
BTC: bc1quwwnec87tukn9j93spr4de7mctvexpftpwu09d
USDT (Tron): THXiCmfr6D4mqAfd4La9EQ5THCx7WsR143
