Protocols¶
Wire-level specifications for Leyline's custom libp2p stream protocols.
Protocol Summary¶
| Protocol | ID | Transport | Purpose |
|---|---|---|---|
| Peer Exchange | /leyline/peer-exchange/1.0.0 | Length-prefixed JSON | Peer table synchronization |
| Ledger Sync | /leyline/ledger-sync/1.0.0 | Length-prefixed JSON | Shared ledger synchronization |
| Discovery | /leyline/discovery/1.0.0 | Length-prefixed JSON | Service query/advertisement |
| Direct Message | /leyline/direct/1.0.0 | Length-prefixed JSON + binary | Encrypted point-to-point messaging |
All protocols use it-pipe and it-length-prefixed for framed async I/O over libp2p streams.
Peer Exchange Protocol¶
Protocol ID: /leyline/peer-exchange/1.0.0
Grows the mesh beyond direct seed connections by exchanging known peer tables.
Message Types¶
Request (initiator sends):
{
"type": "request",
"peers": [PeerRecord],
"senderPeerId": "12D3KooW...",
"timestamp": 1700000000000
}
Response (responder sends):
{
"type": "response",
"peers": [PeerRecord],
"senderPeerId": "12D3KooW...",
"timestamp": 1700000000001
}
PeerRecord:
{
"peerId": "12D3KooW...",
"multiaddrs": ["/ip4/10.0.0.1/tcp/9876"],
"pubkeyHex": "a3f0c1b2...",
"offeredTags": ["skill:code", "lang:ts"],
"lastSeen": 1700000000000,
"signature": "..."
}
Exchange Flow¶
Node A Node B
| |
| dialProtocol(PEX) |
|------------------------------->|
| |
| Request{peers: A's table} |
|------------------------------->|
| | Merge A's peers
| | into B's table
| Response{peers: B's table} |
|<-------------------------------|
| Merge B's peers |
| into A's table |
Parameters¶
| Parameter | Default | Description |
|---|---|---|
| Max peers in table | 500 | Records beyond this trigger 10% eviction |
| Max peer age | 30 minutes | Stale peers evicted |
| Exchange interval | 30 seconds | Periodic exchange frequency |
| Peers per exchange | 50 | Randomly sampled from table |
| Max concurrent exchanges | 5 | Parallel exchange limit |
Ledger Sync Protocol¶
Protocol ID: /leyline/ledger-sync/1.0.0
Synchronizes shared ledger entries between peers.
Message Types¶
RangeRequest (pull entries):
{
"type": "range-request",
"senderPeerId": "12D3KooW...",
"startIndex": 42,
"endIndex": 141,
"timestamp": 1700000000000
}
RangeResponse (return entries):
{
"type": "range-response",
"entries": [SerializedEntry],
"totalEntries": 500,
"timestamp": 1700000000001
}
PushEntry (push for validation):
ConfirmEntry (confirm validated entry):
{
"type": "confirm-entry",
"entryIndex": 42,
"confirmerPubkey": "a3f0c1b2...",
"timestamp": 1700000000001
}
Sync Flow¶
Node A Node B
| |
| RangeRequest{101, 200} |
|---------------------------------->|
| |
| RangeResponse{entries[101-150]} |
|<----------------------------------|
| (validate & ingest entries) |
Push + Confirm Flow¶
Node A Node B
| |
| PushEntry{entry} |
|---------------------------------->|
| | Validate signature
| | Ingest entry
| | Add own confirmation
| ConfirmEntry{index, pubkey} |
|<----------------------------------|
Periodic Sync¶
Every 60 seconds:
- Get local entry count
- For each connected peer, request entries
[localCount+1, localCount+100] - Validate each entry (Ed25519 signature verification)
- Ingest valid entries
Discovery Protocol¶
Protocol ID: /leyline/discovery/1.0.0
Structured capability discovery for agents offering services.
ServiceDescriptor¶
interface ServiceDescriptor {
id: string; // Unique service ID
name: string; // Human-readable name
tags: string[]; // Capability tags
description: string;
providerPubkey: string; // Ed25519 pubkey (hex)
providerPeerId: string; // libp2p peer ID
multiaddrs: string[]; // Reachable addresses
advertisedAt: number; // Unix ms
ttl: number; // Time-to-live (default 5 min)
metadata: Record<string, string>;
signature?: string; // Ed25519 signature
}
Message Types¶
- query: Search peer's registry for matching services (by tags or name)
- result: Return matching descriptors
- advertisement: Push a descriptor to a peer (unsolicited)
Re-advertisement¶
Services are re-advertised every 4 minutes to stay fresh (5-minute TTL). Expired services are pruned from the registry.
Direct Message Protocol¶
Protocol ID: /leyline/direct/1.0.0
Point-to-point encrypted messaging with relay fallback.
Wire Envelope¶
interface DirectEnvelope {
payload: Uint8Array; // Encrypted or plaintext message
targetPeerId: string;
senderPeerId: string;
timestamp: number;
isRelay: boolean; // True if relayed
hopsRemaining: number; // Relay TTL
encrypted: boolean;
nonce?: Uint8Array; // 24-byte XChaCha20 nonce
senderPubkeyHex?: string; // For decryption
visitedPeers?: string[]; // Loop prevention
}
Encryption¶
- Convert Ed25519 keys to X25519 (Montgomery form)
- Compute shared secret via X25519 ECDH
- Encrypt with XChaCha20-Poly1305 (24-byte random nonce)
Relay Fallback¶
When direct connection to the target fails:
- Message is wrapped in a relay envelope with
isRelay: true - Sent to connected peers with decreasing
hopsRemaining - Each relay peer checks
visitedPeersfor loop prevention - Only the target can decrypt the payload