diff options
Diffstat (limited to '01.md')
| -rw-r--r-- | 01.md | 59 |
1 files changed, 36 insertions, 23 deletions
| @@ -4,7 +4,7 @@ NIP-01 | |||
| 4 | Basic protocol flow description | 4 | Basic protocol flow description |
| 5 | ------------------------------- | 5 | ------------------------------- |
| 6 | 6 | ||
| 7 | `draft` `mandatory` `author:fiatjaf` `author:distbit` `author:scsibug` `author:kukks` `author:jb55` `author:semisol` `author:cameri` `author:Giszmo` | 7 | `draft` `mandatory` |
| 8 | 8 | ||
| 9 | This NIP defines the basic protocol that should be implemented by everybody. New NIPs may add new optional (or mandatory) fields and messages and features to the structures and flows described here. | 9 | This NIP defines the basic protocol that should be implemented by everybody. New NIPs may add new optional (or mandatory) fields and messages and features to the structures and flows described here. |
| 10 | 10 | ||
| @@ -14,7 +14,7 @@ Each user has a keypair. Signatures, public key, and encodings are done accordin | |||
| 14 | 14 | ||
| 15 | The only object type that exists is the `event`, which has the following format on the wire: | 15 | The only object type that exists is the `event`, which has the following format on the wire: |
| 16 | 16 | ||
| 17 | ```json | 17 | ```jsonc |
| 18 | { | 18 | { |
| 19 | "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>, | 19 | "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>, |
| 20 | "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>, | 20 | "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>, |
| @@ -22,14 +22,14 @@ The only object type that exists is the `event`, which has the following format | |||
| 22 | "kind": <integer between 0 and 65535>, | 22 | "kind": <integer between 0 and 65535>, |
| 23 | "tags": [ | 23 | "tags": [ |
| 24 | [<arbitrary string>...], | 24 | [<arbitrary string>...], |
| 25 | ... | 25 | // ... |
| 26 | ], | 26 | ], |
| 27 | "content": <arbitrary string>, | 27 | "content": <arbitrary string>, |
| 28 | "sig": <64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field> | 28 | "sig": <64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field> |
| 29 | } | 29 | } |
| 30 | ``` | 30 | ``` |
| 31 | 31 | ||
| 32 | To obtain the `event.id`, we `sha256` the serialized event. The serialization is done over the UTF-8 JSON-serialized string (with no white space or line breaks between the fields) of the following structure: | 32 | To obtain the `event.id`, we `sha256` the serialized event. The serialization is done over the UTF-8 JSON-serialized string (which is described below) of the following structure: |
| 33 | 33 | ||
| 34 | ``` | 34 | ``` |
| 35 | [ | 35 | [ |
| @@ -42,21 +42,32 @@ To obtain the `event.id`, we `sha256` the serialized event. The serialization is | |||
| 42 | ] | 42 | ] |
| 43 | ``` | 43 | ``` |
| 44 | 44 | ||
| 45 | To prevent implementation differences from creating a different event ID for the same event, the following rules MUST be followed while serializing: | ||
| 46 | - No whitespace, line breaks or other unnecessary formatting should be included in the output JSON. | ||
| 47 | - No characters except the following should be escaped, and instead should be included verbatim: | ||
| 48 | - A line break, `0x0A`, as `\n` | ||
| 49 | - A double quote, `0x22`, as `\"` | ||
| 50 | - A backslash, `0x5C`, as `\\` | ||
| 51 | - A carriage return, `0x0D`, as `\r` | ||
| 52 | - A tab character, `0x09`, as `\t` | ||
| 53 | - A backspace, `0x08`, as `\b` | ||
| 54 | - A form feed, `0x0C`, as `\f` | ||
| 55 | - UTF-8 should be used for encoding. | ||
| 56 | |||
| 45 | ### Tags | 57 | ### Tags |
| 46 | 58 | ||
| 47 | Each tag is an array of strings of arbitrary size, with some conventions around them. Take a look at the example below: | 59 | Each tag is an array of one or more strings, with some conventions around them. Take a look at the example below: |
| 48 | 60 | ||
| 49 | ```json | 61 | ```jsonc |
| 50 | { | 62 | { |
| 51 | ..., | ||
| 52 | "tags": [ | 63 | "tags": [ |
| 53 | ["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"], | 64 | ["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"], |
| 54 | ["p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"], | 65 | ["p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"], |
| 55 | ["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"], | 66 | ["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"], |
| 56 | ["alt", "reply"], | 67 | ["alt", "reply"], |
| 57 | ... | 68 | // ... |
| 58 | ], | 69 | ], |
| 59 | ... | 70 | // ... |
| 60 | } | 71 | } |
| 61 | ``` | 72 | ``` |
| 62 | 73 | ||
| @@ -70,13 +81,13 @@ This NIP defines 3 standard tags that can be used across all event kinds with th | |||
| 70 | - for a parameterized replaceable event: `["a", <kind integer>:<32-bytes lowercase hex of a pubkey>:<d tag value>, <recommended relay URL, optional>]` | 81 | - for a parameterized replaceable event: `["a", <kind integer>:<32-bytes lowercase hex of a pubkey>:<d tag value>, <recommended relay URL, optional>]` |
| 71 | - for a non-parameterized replaceable event: `["a", <kind integer>:<32-bytes lowercase hex of a pubkey>:, <recommended relay URL, optional>]` | 82 | - for a non-parameterized replaceable event: `["a", <kind integer>:<32-bytes lowercase hex of a pubkey>:, <recommended relay URL, optional>]` |
| 72 | 83 | ||
| 73 | As a convention, all single-letter (only english alphabet letters: a-z, A-Z) key tags are expected to be indexed by relays, such that it is possible, for example, to query or subscribe to events that reference the event `"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"` by using the `{"#e": "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"}` filter. | 84 | As a convention, all single-letter (only english alphabet letters: a-z, A-Z) key tags are expected to be indexed by relays, such that it is possible, for example, to query or subscribe to events that reference the event `"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"` by using the `{"#e": ["5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"]}` filter. |
| 74 | 85 | ||
| 75 | ### Kinds | 86 | ### Kinds |
| 76 | 87 | ||
| 77 | Kinds specify how clients should interpret the meaning of each event and the other fields of each event (e.g. an `"r"` tag may have a meaning in an event of kind 1 and an entirely different meaning in an event of kind 10002). Each NIP may define the meaning of a set of kinds that weren't defined elsewhere. This NIP defines two basic kinds: | 88 | Kinds specify how clients should interpret the meaning of each event and the other fields of each event (e.g. an `"r"` tag may have a meaning in an event of kind 1 and an entirely different meaning in an event of kind 10002). Each NIP may define the meaning of a set of kinds that weren't defined elsewhere. This NIP defines two basic kinds: |
| 78 | 89 | ||
| 79 | - `0`: **metadata**: the `content` is set to a stringified JSON object `{name: <username>, about: <string>, picture: <url, string>}` describing the user who created the event. A relay may delete older events once it gets a new one for the same pubkey. | 90 | - `0`: **metadata**: the `content` is set to a stringified JSON object `{name: <username>, about: <string>, picture: <url, string>}` describing the user who created the event. [Extra metadata fields](24.md#kind-0) may be set. A relay may delete older events once it gets a new one for the same pubkey. |
| 80 | - `1`: **text note**: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. Clients should also not parse content as those. | 91 | - `1`: **text note**: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. Clients should also not parse content as those. |
| 81 | 92 | ||
| 82 | And also a convention for kind ranges that allow for easier experimentation and flexibility of relay implementation: | 93 | And also a convention for kind ranges that allow for easier experimentation and flexibility of relay implementation: |
| @@ -96,28 +107,24 @@ These are just conventions and relay implementations may differ. | |||
| 96 | 107 | ||
| 97 | Relays expose a websocket endpoint to which clients can connect. Clients SHOULD open a single websocket connection to each relay and use it for all their subscriptions. Relays MAY limit number of connections from specific IP/client/etc. | 108 | Relays expose a websocket endpoint to which clients can connect. Clients SHOULD open a single websocket connection to each relay and use it for all their subscriptions. Relays MAY limit number of connections from specific IP/client/etc. |
| 98 | 109 | ||
| 99 | ### Meaning of WebSocket status codes | ||
| 100 | |||
| 101 | - When a websocket is closed by the relay with a status code `4000` that means the client shouldn't try to connect again. | ||
| 102 | |||
| 103 | ### From client to relay: sending events and creating subscriptions | 110 | ### From client to relay: sending events and creating subscriptions |
| 104 | 111 | ||
| 105 | Clients can send 3 types of messages, which must be JSON arrays, according to the following patterns: | 112 | Clients can send 3 types of messages, which must be JSON arrays, according to the following patterns: |
| 106 | 113 | ||
| 107 | * `["EVENT", <event JSON as defined above>]`, used to publish events. | 114 | * `["EVENT", <event JSON as defined above>]`, used to publish events. |
| 108 | * `["REQ", <subscription_id>, <filters JSON>...]`, used to request events and subscribe to new updates. | 115 | * `["REQ", <subscription_id>, <filters1>, <filters2>, ...]`, used to request events and subscribe to new updates. |
| 109 | * `["CLOSE", <subscription_id>]`, used to stop previous subscriptions. | 116 | * `["CLOSE", <subscription_id>]`, used to stop previous subscriptions. |
| 110 | 117 | ||
| 111 | `<subscription_id>` is an arbitrary, non-empty string of max length 64 chars, that should be used to represent a subscription. Relays should manage `<subscription_id>`s independently for each WebSocket connection; even if `<subscription_id>`s are the same string, they should be treated as different subscriptions for different connections. | 118 | `<subscription_id>` is an arbitrary, non-empty string of max length 64 chars. It represents a subscription per connection. Relays MUST manage `<subscription_id>`s independently for each WebSocket connection. `<subscription_id>`s are not guaranteed to be globally unique. |
| 112 | 119 | ||
| 113 | `<filters>` is a JSON object that determines what events will be sent in that subscription, it can have the following attributes: | 120 | `<filtersX>` is a JSON object that determines what events will be sent in that subscription, it can have the following attributes: |
| 114 | 121 | ||
| 115 | ```json | 122 | ```json |
| 116 | { | 123 | { |
| 117 | "ids": <a list of event ids>, | 124 | "ids": <a list of event ids>, |
| 118 | "authors": <a list of lowercase pubkeys, the pubkey of an event must be one of these>, | 125 | "authors": <a list of lowercase pubkeys, the pubkey of an event must be one of these>, |
| 119 | "kinds": <a list of a kind numbers>, | 126 | "kinds": <a list of a kind numbers>, |
| 120 | "#<single-letter (a-zA-Z)>": <a list of tag values, for #e — a list of event ids, for #p — a list of event pubkeys etc>, | 127 | "#<single-letter (a-zA-Z)>": <a list of tag values, for #e — a list of event ids, for #p — a list of pubkeys, etc.>, |
| 121 | "since": <an integer unix timestamp in seconds, events must be newer than this to pass>, | 128 | "since": <an integer unix timestamp in seconds, events must be newer than this to pass>, |
| 122 | "until": <an integer unix timestamp in seconds, events must be older than this to pass>, | 129 | "until": <an integer unix timestamp in seconds, events must be older than this to pass>, |
| 123 | "limit": <maximum number of events relays SHOULD return in the initial query> | 130 | "limit": <maximum number of events relays SHOULD return in the initial query> |
| @@ -140,24 +147,30 @@ The `limit` property of a filter is only valid for the initial query and MUST be | |||
| 140 | 147 | ||
| 141 | ### From relay to client: sending events and notices | 148 | ### From relay to client: sending events and notices |
| 142 | 149 | ||
| 143 | Relays can send 4 types of messages, which must also be JSON arrays, according to the following patterns: | 150 | Relays can send 5 types of messages, which must also be JSON arrays, according to the following patterns: |
| 144 | 151 | ||
| 145 | * `["EVENT", <subscription_id>, <event JSON as defined above>]`, used to send events requested by clients. | 152 | * `["EVENT", <subscription_id>, <event JSON as defined above>]`, used to send events requested by clients. |
| 146 | * `["OK", <event_id>, <true|false>, <message>]`, used to indicate acceptance or denial of an `EVENT` message. | 153 | * `["OK", <event_id>, <true|false>, <message>]`, used to indicate acceptance or denial of an `EVENT` message. |
| 147 | * `["EOSE", <subscription_id>]`, used to indicate the _end of stored events_ and the beginning of events newly received in real-time. | 154 | * `["EOSE", <subscription_id>]`, used to indicate the _end of stored events_ and the beginning of events newly received in real-time. |
| 155 | * `["CLOSED", <subscription_id>, <message>]`, used to indicate that a subscription was ended on the server side. | ||
| 148 | * `["NOTICE", <message>]`, used to send human-readable error messages or other things to clients. | 156 | * `["NOTICE", <message>]`, used to send human-readable error messages or other things to clients. |
| 149 | 157 | ||
| 150 | This NIP defines no rules for how `NOTICE` messages should be sent or treated. | 158 | This NIP defines no rules for how `NOTICE` messages should be sent or treated. |
| 151 | 159 | ||
| 152 | - `EVENT` messages MUST be sent only with a subscription ID related to a subscription previously initiated by the client (using the `REQ` message above). | 160 | - `EVENT` messages MUST be sent only with a subscription ID related to a subscription previously initiated by the client (using the `REQ` message above). |
| 153 | - `OK` messages MUST be sent in response to `EVENT` messages received from clients, they must have the 3rd parameter set to `true` when an event has been accepted by the relay, `false` otherwise. The 4th parameter MUST always be present, but MAY be an empty string when the 3rd is `true`, otherwise it MUST be a string formed by a machine-readable single-word prefix followed by a `:` and then a human-readable message. The standardized machine-readable prefixes are: `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, and `error` for when none of that fits. Some examples: | 161 | - `OK` messages MUST be sent in response to `EVENT` messages received from clients, they must have the 3rd parameter set to `true` when an event has been accepted by the relay, `false` otherwise. The 4th parameter MUST always be present, but MAY be an empty string when the 3rd is `true`, otherwise it MUST be a string formed by a machine-readable single-word prefix followed by a `:` and then a human-readable message. Some examples: |
| 154 | |||
| 155 | * `["OK", "b1a649ebe8...", true, ""]` | 162 | * `["OK", "b1a649ebe8...", true, ""]` |
| 156 | * `["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]` | 163 | * `["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]` |
| 157 | * `["OK", "b1a649ebe8...", true, "duplicate: already have this event"]` | 164 | * `["OK", "b1a649ebe8...", true, "duplicate: already have this event"]` |
| 158 | * `["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]` | 165 | * `["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]` |
| 159 | * `["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]` | 166 | * `["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]` |
| 160 | * `["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]` | 167 | * `["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]` |
| 161 | * `["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time. Is your system clock in sync?"]` | 168 | * `["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time"]` |
| 162 | * `["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]` | 169 | * `["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]` |
| 163 | * `["OK", "b1a649ebe8...", false, "error: could not connect to the database"]` | 170 | * `["OK", "b1a649ebe8...", false, "error: could not connect to the database"]` |
| 171 | - `CLOSED` messages MUST be sent in response to a `REQ` when the relay refuses to fulfill it. It can also be sent when a relay decides to kill a subscription on its side before a client has disconnected or sent a `CLOSE`. This message uses the same pattern of `OK` messages with the machine-readable prefix and human-readable message. Some examples: | ||
| 172 | * `["CLOSED", "sub1", "duplicate: sub1 already opened"]` | ||
| 173 | * `["CLOSED", "sub1", "unsupported: filter contains unknown elements"]` | ||
| 174 | * `["CLOSED", "sub1", "error: could not connect to the database"]` | ||
| 175 | * `["CLOSED", "sub1", "error: shutting down idle subscription"]` | ||
| 176 | - The standardized machine-readable prefixes for `OK` and `CLOSED` are: `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, and `error` for when none of that fits. | ||