Relay Operators

A relay operator runs a hosted inbox service. Users who are frequently offline (mobile cipherclerks, IoT agents, intermittent peers) subscribe to a relay operator. The relay buffers store-and-forward messages in MerkleQueue-backed inboxes, provides cryptographic delivery proofs, and earns fees for the service.

What is a Relay Operator?

Requirements

Quick Start

# Initialize the node data directory (generates operator keypair)
dregg-node init --data-dir ~/.dregg

# Start the relay operator service
dregg-node relay \
  --bond 10000 \
  --port 3100 \
  --state-file ./relay-state.json \
  --data-dir ~/.dregg

The relay service starts an HTTP API on the specified port. It reads the operator identity from ~/.dregg/node.key.

Configuration Options

FlagDefaultDescription
--port3100HTTP API listen port
--bond10000Bond amount in computrons (operator stake)
--max-capacity100000Maximum total inbox capacity to host
--gc-interval300GC interval in seconds
--message-ttl1000Message TTL in blocks (expired messages are GC'd)
--max-delivery-latency50SLA: max blocks before delivery is required
--state-file./relay-state.jsonPath for persistent relay state
--data-dir~/.dreggData directory (operator key location)
--default-inbox-capacity100Default capacity for new inbox subscriptions
--default-min-deposit100Default minimum deposit per message
--min-message-deposit100Global minimum deposit per message (computrons)
--subscription-fee1000One-time fee for creating an inbox

HTTP API Endpoints

MethodPathDescription
GET/relay/statusOperator info: bond, hosted inboxes, earnings, health
POST/relay/subscribeCreate a hosted inbox (user pays subscription fee)
DELETE/relay/unsubscribeRemove an inbox (remaining messages refunded)
POST/relay/send/:destEnqueue a message (sender pays deposit)
GET/relay/drainDrain your inbox (authenticated, returns messages + proofs)
GET/relay/inbox/:id/statusCheck inbox status (capacity, pending, root)
GET/relay/proof/:msg_idGet the DequeueProof for a delivered message

Economics

Revenue Sources

Fee Flow

Sender deposits 1000 computrons with a message
  |
  +-- Message delivered within TTL:
  |     Deposit goes to inbox owner (compensation for reading)
  |
  +-- Message expires (GC):
        90% refunded to sender
        10% kept by relay operator as fee

Bond Economics

The bond requirement scales linearly with committed capacity: required_bond = total_committed_capacity * 100 computrons. If an operator becomes underbonded (e.g., bond is slashed), they cannot accept new inboxes until the bond is topped up.

Disputes and Slashing

If a relay operator fails to deliver a message within the SLA window (max_delivery_latency blocks), a sender can file a DeliveryDispute:

  1. Sender proves they enqueued (provides old queue root + enqueue receipt)
  2. Operator must respond with a valid DequeueProof within the SLA window
  3. If operator cannot produce proof: slashed (bond / active_inboxes)
  4. If operator produces valid proof: dispute dismissed

Slashing is proportional: slash_amount = bond / active_inbox_count. An operator hosting 10 inboxes with a 100,000 computron bond risks losing 10,000 computrons per failed delivery dispute.

Monitoring

Use GET /relay/status to monitor operator health:

curl http://localhost:3100/relay/status | jq .

{
  "operator_id": "aa0011...",
  "bond": 100000,
  "required_bond": 50000,
  "is_underbonded": false,
  "active_inboxes": 5,
  "total_pending_messages": 142,
  "earned_fees": 4200,
  "max_delivery_latency_blocks": 50,
  "current_height": 12450,
  "messages_delivered": 8923,
  "messages_received": 9065,
  "gc_interval_secs": 300
}

What to Watch

Scaling

Discovery (Governed Namespace)

Relay operators register in the governed namespace so that clients can discover available relays. The namespace entry includes the operator's public key, endpoint URL, fee policy, and current capacity availability. Clients query the namespace to find a relay that meets their needs (price, capacity, SLA).