# Relay Descriptor Core Object

[Client–relay protocol](../README.md) · [Core object index](README.md)

## `RelayDescriptor`

`RelayDescriptor` is a verifiable service identity declaration for a public relay, published through the client–relay interface and exchanged during the [relay Noise handshake](../../relay-dht/concepts/connection-and-authentication.md#security-protocol-and-handshake-format). It binds the on-chain `relay_id`, corresponding Neo public key, client endpoints, libp2p Peer ID, protocol capabilities, and validity period into one signed object. Clients use it to verify endpoint/relay-identity binding. Other relays directly verify the descriptor supplied in the handshake and use the current Registry record to confirm its binding to the connection's Peer ID. Relay network eligibility requires an `active` Registry record and a valid RelayDescriptor.

Peer ID is derived from the relay's libp2p Peer public key under libp2p rules and identifies its secure-connection identity. `relay_id` identifies its Neo account identity.

```json
{
  "$type": "meshline.relay.descriptor",
  "relay_id": "0x1234567890abcdef1234567890abcdef12345678",
  "public_key": "base64url...",
  "endpoints": [
    "https://relay.example.com/meshline/v1",
    "wss://relay.example.com/meshline/v1",
    "/dns4/relay.example.com/tcp/4201/p2p/12D3KooW..."
  ],
  "capabilities": [
    "channel.host.v1"
  ],
  "expires_at": 1730086400,
  "relay_signature": "base64url..."
}
```

| Field | Type | Required | Semantics and constraints |
|---|---|---|---|
| `$type` | string | Yes | Fixed as `meshline.relay.descriptor` |
| `relay_id` | string | Yes | [Relay ID](../../registry/core-objects.md#relay-id) in the Registry record |
| `public_key` | string | Yes | 33-byte SEC1 compressed `secp256r1` public key, unpadded base64url; MUST derive `relay_id` |
| `endpoints` | array&lt;string&gt; | Yes | Nonempty set of endpoint addresses; see [Relay endpoint addresses](#relay-endpoint-addresses) |
| `capabilities` | array&lt;string&gt; | No | Published capability declarations; empty or omitted if none; at most 64 entries, each a nonempty string of at most 128 UTF-8 bytes; compare complete strings case-sensitively with no duplicates; order has no semantic meaning, and unknown names MUST be ignored |
| `expires_at` | integer | Yes | Expiry time; the descriptor is invalid once the current time reaches or exceeds it |
| `relay_signature` | string | Yes | 64-byte signature generated by the Neo N3 relay account corresponding to `relay_id` under [Account signatures](../../general.md#account-signatures), unpadded base64url |

Signing excludes root `relay_signature` and constructs input under [Network-bound JSON inputs](../../general.md#network-bound-json-inputs).

### Service Requirements and Capability Declarations

Public relays MUST fully provide relay discovery and identity authentication, the HTTPS base client API, device and profile state, account routes, DHT queries, inter-relay forwarding, message sending, bounded-retention account message timelines, and HTTP synchronization.

This specification defines these channel and group hosting capabilities:

| Capability identifier | Service and implementation requirements |
|---|---|
| `channel.host.v1` | MUST be declared when offering channel hosting; requires all interfaces with HTTP forms in the [Channel method index](../channels/README.md#method-index) and verification of remote devices connecting directly to the channel relay under [`auth.device.verify`](../methods/authentication-and-sessions.md#authdeviceverify); with a WSS endpoint, channel subscriptions and [channel notifications](../channels/README.md#notification-index) are also required |
| `group.host.v1` | MUST be declared when offering group hosting; requires all interfaces with HTTP forms in the [Group method index](../groups/README.md#method-index) and verification of remote devices connecting directly to the group relay under [`auth.device.verify`](../methods/authentication-and-sessions.md#authdeviceverify); with a WSS endpoint, group subscriptions and [group notifications](../groups/README.md#notification-index) are also required |

## Relay Endpoint Addresses

### Address Format and Validation

This protocol defines the following dialable address formats, each of which also determines its transport:

| Address format | Purpose |
|---|---|
| `https://...` | Base address for the public client HTTP API |
| `wss://...` | Complete client WebSocket connection address provided by a public relay |
| libp2p multiaddr containing `/tcp/` and `/p2p/<peer-id>` | Inter-relay connections |

A public relay MUST provide at least one HTTPS address and one libp2p TCP multiaddr. A WSS address indicates complete support for the client WebSocket transport and notifications under [WebSocket JSON-RPC](../methods/conventions.md#websocket-json-rpc); without one, that mechanism is unavailable.

Every HTTPS candidate MUST meet all format constraints of the [Registry entry](../../registry/core-objects.md#relayentry). WSS candidates use the `wss` scheme with the same remaining constraints. Both MUST be absolute URLs with valid hosts; even an empty query or fragment is forbidden. For HTTP URL construction and WSS connections, see [Method and request mapping](../methods/conventions.md#method-and-request-mapping).

For the HTTPS, WSS, and libp2p TCP formats defined here, any malformed candidate invalidates the entire descriptor; such errors MUST NOT be ignored as unknown transports. Verifiers MUST NOT accept a descriptor after filling in paths, removing prohibited parts, or rewriting addresses; signature verification uses original addresses. Authentication origin is separately calculated under [Relay origin](../methods/authentication-and-sessions.md#relay-origin-calculation) and does not replace endpoint format checks.

For transports not defined here, verifiers MUST retain the original address and its array position for signature verification, but ignore it in this protocol. They MUST NOT connect to it or count it toward required addresses or Peer ID binding checks, and MUST NOT reject the whole descriptor solely because it is present.

Each address array item MUST be a nonempty string, with no duplicates. Array order carries no business semantics, but signatures preserve the actual order.

### Candidate Selection and Retries

A transport may have multiple candidate addresses; business connections MUST pass that transport's identity and protocol checks. Once a server has returned a valid protocol response, whether another address may be tried depends on the method's error handling and duplicate-request rules. Callers MUST NOT automatically treat business errors as address connection failures.

After all candidates for one transport in a `RelayDescriptor` fail, callers are advised to refresh Registry state and `RelayDescriptor` to check for changed eligibility or service addresses. All candidates belong to the same `relay_id`; changing addresses does not change the target relay or imply a standby relay or service migration.

For writes that may already have been accepted, handling after an address change follows the method's duplicate-request and retry rules. When a method explicitly allows idempotent retries, a caller that meets identity and session requirements at the new endpoint may resubmit the unchanged request to the same relay; idempotency retention, current authorization, and other conditions still apply. Other methods continue to require their respective reads, synchronization, or status queries before deciding whether to proceed. Changing addresses does not itself authorize replay.

## Relay Descriptor Validation Rules

Verifiers MUST:

1. Derive the Neo single-signature account from `public_key` and confirm its script hash equals `relay_id`.
2. Verify the Neo account signature.
3. Confirm that the corresponding Registry record has `status` equal to `active`.
4. Validate `endpoints` under [Relay endpoint addresses](#relay-endpoint-addresses), ignoring unknown transports, and confirm at least one valid HTTPS address and one valid libp2p TCP multiaddr.
5. Confirm `RelayDescriptor` has not expired.
6. Confirm `capabilities` meets its field constraints, and confirm the relevant declaration before using an optional capability.
7. Confirm that all libp2p TCP multiaddrs contain a Peer ID and that all such Peer IDs are identical.

Clients using HTTPS or WSS MUST select candidates from `endpoints` that have passed these checks. Origin calculation, session binding, and authentication on new WSS connections follow [Session authentication](../methods/authentication-and-sessions.md#session-authentication). After switching to another origin, clients MUST reauthenticate there in a mode allowed by the method before calling a session-requiring method.

Relays connecting to libp2p TCP addresses in this descriptor MUST complete handshake declarations and identity checks under [Relay connections and identity authentication](../../relay-dht/concepts/connection-and-authentication.md). Every candidate's Peer ID MUST match the actual secure connection's Peer ID, and the remote MUST support the [Relay DHT protocol](../../relay-dht/README.md) and [Relay RPC protocol](../../relay-rpc/README.md) defined here. Connections that fail these conditions MUST reject protocol negotiation or close. Identity discovery beginning with DHT candidates follows that connection specification. For transport failure handling, descriptor refresh, and request replay constraints, see [Relay endpoint addresses](relay-descriptor.md#relay-endpoint-addresses).
