Skip to content

Commit

Permalink
LSPS0: Transport layer protocol description.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZmnSCPxj-jr committed Mar 24, 2023
1 parent 92b0ed9 commit 5dade87
Showing 1 changed file with 278 additions and 0 deletions.
278 changes: 278 additions & 0 deletions LSPS0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# LSPS0 Transport Layer

| Name | `base_api` |
| ------- | ---------------- |
| Version | 1 |

## Motivation

The transport layer describes how a client is able to request
services from the LSP.

### Actors

'LSP' is the API provider, and acts as the server.
'Client' is the API consumer.

## Protocol

### Lightning Peer-To-Peer Transport

The Lightning Network [BOLT8][] specification describes the transport
layer for Lightning Network peer-to-peer messages.

[BOLT8]: https://github.com/lightning/bolts/blob/f7dcc32694b8cd4f3a1768b904f58cb177168f29/08-transport.md

Lightning Network BOLT8 describes messages as having two components:

* A 16-bit message ID (encoded in big-endian).
* A variable-length message payload (the remainder of the message).

LSPS messages and access to LSP endpoints is via BOLT8 messages.

> **Rationale** All clients and LSPs are expected to be Lightning
> Network participants, and need to somehow talk using the BOLT8
> protocol.
> Thus, this is not an additional dependency for any client and
> any LSP, the way an HTTP(S) or gRPC protocol would pull in
> additional dependencies.
For LSPS0, the message ID SHALL be 37913 (`lsps0_message_id`).
All LSPS messages use only this message ID.

> **Rationale** We indicate a single message ID as this reduces
> the "footprint" of all LSPS specifications to only that single
> message ID, increasing the probability that other protocols
> using the Lightning BOLT8 peer-to-peer transport will not
> conflict with the LSPS specifications.
> The message ID 37913 is odd in order to comply with the "it's
> OK to be odd" rule, and is in the 32768 to 65535 range reserved
> for extensions of the BOLT protocol.
> Some implementations, such as Core Lightning, only expose
> odd-numbered messages to custom message handlers.
> The message ID was otherwise selected by random and has no
> special meaning.
The payload contains the UTF-8 encoding of a complete JSON
object.

If a client or LSP receives a BOLT8 message with message ID
37913:

* If the payload does not parse as a complete JSON object
(i.e. a JSON key-value store or dictionary), MUST disconnect
from the peer and ignore the message.
* If the payload parses as more than a single complete JSON
object, MUST disconnect from the peer and ignore the message.
* If any byte in the payload is 0, MUST disconnect from the
peer and ignore the message.
* MUST NOT expect the payload to be terminated by a NUL
character (0 byte).

> **Rationale** Requiring a single complete JSON object
> simplifies handling of messages, so that a single message
> maps to a single request or response.
> C uses the NUL character as a string terminator and thus
> embedded 0 bytes may cause problems in implementations
> that pass the JSON string to C code.
> Conversely, we do not require the payload to be terminated
> by a 0 byte / NUL character as it is unnecessary in many
> modern non-C-based languages; C code can copy the buffer
> and append the NUL character if necessary, as the payload
> size is known.
The JSON object embedded in the message payload is defined
by the [JSON-RPC 2.0][] protocol.

[JSON-RPC 2.0]: https://www.jsonrpc.org/specification

The LSP acts as a JSON-RPC 2.0 server, while the client acts
as a JSON-RPC 2.0 client.

> **Rationale** JSON is a simple format that is easy to
> extend and is extensively supported.
> The Lightning Network peer-to-peer transport protocol in
> BOLT8 is not inherently a request-response protocol like
> Lightning or gRPC, and JSON-RPC 2.0 describes a
> JSON-based protocol that builds a request-response
> protocol from a simple tunnel, with message ID 37913
> acting as that tunnel.
> JSON-RPC 2.0 is simple to implement.
> Although BOLT8 messages are limited to payloads of 65533
> bytes, it is expected that both requests and responses
> would be far below that limit, and thus the ability to
> "cut" a large object across multiple messages, the
> use of a compression algorithm, and the use of a binary
> format instead of JSON, are all considered unnecessary.
The client:

* MUST send single complete JSON-RPC 2.0 request objects,
UTF-8-encoded, as payloads for message ID 37913.
* MUST NOT send JSON-RPC 2.0 notification objects
(i.e. every object it sends must have an `id` field).
* MUST NOT use by-position parameter structures, and MUST
use by-name parameter structures.
* MUST NOT batch multiple JSON-RPC 2.0 request objects in
an array as described in the "Batch" section of the
JSON-RPC 2.0 specification.

> **Rationale** By disallowing by-position parameter
> structures, other LSPS specifications need only to define
> parameter names and not some canonical order of parameters
> for by-position use.
> Having to handle only by-name parameter structures also
> simplifies the LSP code, as it does not have to check
> whether the `params` value is an array or a dictionary,
> and to separately map array elements to `params` keys.
> Batched requests require batched responses according to
> JSON-RPC 2.0, and it may be simpler for LSPs to handle
> unrelated LSPS methods separately without requiring
> re-batching of the responses; it gives a simple "one
> message is one request / response" rule.
The LSP:

* MUST send single complete JSON-RPC 2.0 response objects,
UTF-8-encoded, as payloads for message ID 37913.
* MUST NOT send JSON-RPC 2.0 notification objects
(i.e. every object it sends must have an `id` field).
* MUST respond with an error -32602 if a request `params` field
is not recognized for the given `method`.
* MUST NOT send message ID 37913 unless the peer first sent a
message ID 37913.

> **Rationale** The peer sending message ID 37913 is an
> indicator that it understands the LSPS0 protocol and wishes
> to act as a client.
> If the peer does not send it, then it is not an LSPS client
> and the LSP has no reason to send message ID 37913.
JSON-RPC 2.0 is an asynchronous protocol, and the order
in which the LSP sends responses MAY be different from the
order in which the client sent the requests.

Other LSPS specifications MUST indicate `method` names for
each API endpoint, as well as the key names of the `params`
for each `method`, and the meanings of each parameter.
Other LSPS specifications MUST also describe the possible
error codes for each API endpoint.

Other LSPS specifications SHOULD define `response` values
for its API endpoints that are objects (dictionaries), and
MUST define each key.

LSPs MAY return additional keys in the `response` values
that are not defined in the relevant LSPS specification.
Clients conversely MUST ignore unrecognized keys.

#### Error Handling

JSON-RPC 2.0 `error`s include a `message` field which is a
human-readable error message.

Clients MUST carefully filter error messages of possibly
problematic characters, such as NUL characters, `<`, newlines,
or ASCII control characters, which may cause problems when
displaying in a dynamic context such as an HTML webpage, a
TTY, or C string processing functions.

Clients SHOULD NOT directly expose error `message`s to users
unless users have enabled some kind of "advanced" mode or
"developer" mode.
Clients MAY write them in a log that is accessible to "advanced"
or "developer" mode users.

### Lightning Feature Bit

The [BOLT7][] specification describes the `node_announcement`
gossip message, which includes a `features` bit field.
The [BOLT1][] specification describes the `init` message,
which also includes a `features` bit field.

[BOLT7]: https://github.com/lightning/bolts/blob/f7dcc32694b8cd4f3a1768b904f58cb177168f29/07-routing-gossip.md
[BOLT1]: https://github.com/lightning/bolts/blob/f7dcc32694b8cd4f3a1768b904f58cb177168f29/01-messaging.md

LSPs MUST set the `features` bit numbered 729
(`option_lsps0_lsp`) in both the `init` message on connection
establishment, and in their own advertised `node_announcement`.
Clients MUST NOT set `features` bit numbered 729 in either
context.

> **Rationale** As clients are the one who must initiate any
> message ID 37913 messages before LSPs respond, they need to
> separately discover whether a peer they connect to is
> indeed an LSPS LSP that recognizes that message.
> Broadcasting this as part of gossip allows a client to
> discover new LSPs by simply downloading gossip.
> The bit 729 was chosen by random and has no special meaning.
### LSPS Specification Support Query

The client can determine if an LSP supports a particular LSPS
specification other than LSPS0 via the `method` named
`listprotocols`, which has the following parameters:

```JSON
{
"comment": "This comment is ignored"
}
```

`comment` is an optional string, and is ignored by the LSP.
It defaults to the empty string.

> **Rationale** In addition to allowing clients to determine what
> protocols an LSP supports, this query is also an example of what
> other LSPS specifications need to describe, such as the parameters
> of an API endpoint, the type of each parameter, whether each
> parameter is optional, the default value if the parameter is
> optional but not specified by the client, and what each parameter
> means for the LSP.
The response datum is an object like the below:

```JSON
{
"protocols": [1, 3]
}
```

`protocols` is an array of numbers, indicating the LSPS specification
number for the LSPS specification the LSP supports.
LSPs do not advertise LSPS0 support and 0 MUST NOT appear in the
`protocols` array.

> **Rationale** LSPS0 support is advertised via `features` bit 729
> already, so specifying `0` here is redundant.
> **Non-normative** The example below would not be necessary for other
> LSPS specifications, but gives an idea of how the JSON-RPC 2.0
> protocol would look like, when using this API endpoint.
As a concrete example, a client might send the JSON object below
inside a message ID 37913 in order to query what LSPS protocols
the LSP supports:

```JSON
{
"method": "listprotocols",
"jsonrpc": "2.0",
"id": "example00",
"params": {}
}
```

The LSP could then respond with a message ID 37913 with the following
payload, indicating it supports LSPS1 and LSPS3 (in addition to LSPS0):

```JSON
{
"jsonrpc": "2.0",
"id": "example00",
"result": {
"protocols": [1, 3],
"example-undefined-key-that-clients-should-ignore": true
}
}
```

0 comments on commit 5dade87

Please sign in to comment.