-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LSPS0: Transport layer protocol description.
- Loading branch information
1 parent
0b195ee
commit e550bcf
Showing
1 changed file
with
318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
# 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 | ||
> HTTP(S) or gRPC, and JSON-RPC 2.0 describes a | ||
> JSON-based protocol that builds a request-response | ||
> protocol from a simple tunnel; message ID 37913 acts 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. | ||
|
||
#### Disconnection Handling | ||
|
||
Each connection between a particular client and LSP MUST be | ||
considered a separate JSON-RPC 2.0 tunnel. | ||
This means that the LSP MUST correctly handle the case where | ||
the client uses the same `id` on separate connections. | ||
|
||
This also implies that on disconnection, any responses that | ||
the LSP was not able to send to the client on that connection | ||
are simply lost. | ||
The LSP SHOULD handle this no differently from the client | ||
receiving the response, and then deciding to do nothing | ||
further with the response results. | ||
If the client reconnects after a disconnection, the LSP MUST | ||
NOT send responses for requests sent in the previous | ||
connection, as both connections are independent of each | ||
other. | ||
|
||
Conversely, if the client sees a disconnection from the LSP, | ||
it MUST treat any in-flight requests as having been failed | ||
due to internal server error (error code -32000), as any new | ||
connection the client re-establishes with the LSP would not | ||
allow the LSP to respond to requests from the previous | ||
connection. | ||
|
||
> **Rationale** A different connection with the same client | ||
> may be caused by the client crashing (and thus forgetting | ||
> all the current request `id`s it had in-flight) and then | ||
> being restarted, with the earlier connection (from the | ||
> client instance that crahsed) having its disconnected | ||
> state not be propagated immediately due to vagaries of IP | ||
> packet delivery. | ||
> Similarly, a different connection with the same LSP may | ||
> be caused by the LSP crashing and restarting, and thus | ||
> possibly forgetting in-flight requests. | ||
> Alternately, a disconnection may occur due to an actual | ||
> network partition, but neither the LSP nor the client | ||
> may be equipped to learn that, and so must treat this | ||
> case as if the other side crashed and restarted. | ||
### 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 | ||
} | ||
} | ||
``` |