NIP-66 Winter-2023 Update

This commit is contained in:
dskvr 2023-12-27 13:46:01 +01:00
parent 29a8acb69a
commit 94da0c1014

334
66.md
View File

@ -1,70 +1,171 @@
# NIP-59: Relay Status # NIP-66: Relay Monitoring System
`draft` `optional` `author:dskvr` `draft` `optional`
This NIP defines `30303`, a parameterized replaceable event [NIP-33], referred to as Relay Statuses. Relay Statuses use tags extensively and **may** have `.content` populated with Stringified JSON. This NIP defines two event kinds, `30066` and `10066`.
## Purpose ## `10066`: "Relay Monitor" Events
To store computationally expensive relay meta-data from active relays as events on nostr.
## Personas ### Summary
- **Publishers** generate and push `30303` events. Events **should** be published at a regular interval. Events **must** implement `NIP-40`. `10066` is a replacable event herein referred to as "Relay Monitor" events. These events contain information about a publisher's intent to monitor and/or aggregate relays and publish data as `30066` events.
- **Consumers** aggregate `30303` for insight on relays. Some example consumers are a social client or relay status client.
## schema ### Purpose
To provide a directory of monitors, their intent to publish, their criteria and parameters of monitoring activities.
### `event.tags` ### Schema
Relay status events have **two** (2) required tags and **eight** (8) optional tags. Relay status events introduce **one** (1) new indexable tag (NIP-12) `10066` events have no required tags.
- `"url" == tagUrl[0]` A URL with human readable information about the monitor's activities. If not included, it is assumed these details are included in the monitor's kind 0 for the pubkey that signed the `10066` event.
- `"timeout" == tagTimeout[0]` The timeout values for various tests. `tagTimeout[1]` is the monitor's timeout in milliseconds. `tagTimeout[2]` describes what test the timeout is used for, for example `open`, `read`, `write`, `info`, etc. If no `tagTimeout[2]` is provided, it is assumed the timeout provided applies to all tests.
- `"frequency" == tagFrequency[0]` The frequency at which the monitor publishes 30066 events.
#### Label Tags <sup>NIP-32</sup>
- `role`, for example: `checker` or `aggregator`
_Checks but doesn't aggregate relay lists_
```
[ 'L', 'role' ]
[ 'l', 'checker', 'role' ]
```
- `checks`, should be a lowercase string describing the individual check if role is `checker`. Some examples are: `websocket`, `nip11`, `ssl`, `dns`, `geo`
```
[ 'L', 'checks' ]
[ 'l', 'websocket', 'checks' ]
[ 'l', 'nip11', 'checks' ]
[ 'l', 'ssl', 'checks' ]
[ 'l', 'dns', 'checks' ]
[ 'l', 'geo', 'checks' ]
```
### Other Requirements
- Monitors **should** have a published `10002` event that defines the relays the monitor publishes to.
## `30066`: "Relay Status" Events
### Summary
`30066` is a parameterized replaceable event [NIP-33], referred to as a "Relay" event. These events store the existence and optionally some data relating to the relay.
a
### Purpose
To store useful, computationally expensive relay meta-data about relays.
### NIPs Used
- `NIP-32` Labels
- `NIP-33` Parameterized Replacable Events
- `NIP-40` Expirable Events
- "Yet Another Geo Tag" NIP (Draft)
### Schema
#### `event.content`
**Should** be empty.
#### `event.tags`
Relay status events have **one** (1) required tag.
The tags should be used to represent the Relay's abilities and meta at a point in time. Below the `tags schema` is expressed using pseudo-types for reasons of communication and brevity, for example `tagDescriptor[]`. Tags should be used to represent the Relay's abilities and meta at any given point in time. The "tags schema" is expressed using pseudo-types for reasons of communication and brevity, for example `tagDescriptor[]`. This NIP utilizes `NIP-32` to expose indexable values.
1. `"d" == tagId[0]` The relay URL. The `#d` tag **must** be included in the `event.tags[]` array. `tagId[1]` **must** be the relay websocket URL. The URL **should** be normalized. #### Tags
```json - `"d" == tagId[0]` The relay URL. The `#d` tag **must** be included in the `event.tags[]` array. `tagId[1]` **must** be the relay websocket URL. The URL **should** be normalized.
["d", "wss://history.nostr.watch/"] //tagId[] ```
``` ["d", "wss://history.nostr.watch/"] //tagId[]
2. `"expiration" == tagExpiration[0]` [NIP-40]. The `tagExpiration[]` tag **must** be included in the `event.tags[]` array. `tagExpiration[1]` **should** be set to a future timestamp (seconds) that correlates with the publisher's intended update frequency. ```
```json
["expiration", "1600000000"] //tagExpiration[] - `"rtt-*" == tagRtt[0]` Round-trip time of websocket ping/pong in milliseconds. Example values for `tagRtt[1]` are `open`, `read` and `write`. Where `open` represents the round-trip time forWebsocket to open, `read` represents the round-trip time of a Websocket `REQ` (subscription) message's response, and `write` represents the round-trip time of a Websocket `EVENT` (publish) message and subsequent `ok` message. `tagRtt[2...]` are strings with the millisecond values. At a minimum `tagRtt[2]` **should** be set. When more than one value is provided, values **may** be treated as an array to find `min`, `max`, `average` and `median` values. There **may** be zero `rtt` tags.
``` ```
3. `"t" == tagTopic[0]` Topics relevant to the relay. `tagTopic[]` **may** be included in the `event.tags[]` array. `tagTopic[1]` **should** be a string. There **should** be no more than **fifty (50)** `tagTopic[]` arrays. ["rtt", "open", "201", "190", "540"],
```json ["rtt", "read", "35", "60", "46"],
["t", "bitcoin"] //tagTopic[] ["rtt", "write", "701", "497", "508"]
``` ```
4. `"g" == tagGeo[0]` Relay Geo Data. `tagGeo[]` **may** be included in the `event.tags[]` array. `tagGeo[1]` **must** be string. `tagGeo[2]` **must** be a string and **should** be a label that describes `tagGeo[1]`. There **may** be more than **one (1)** `tagGeo[]` per event.
```json - `"count" == tagCount[0]` Meta values for arbitrary counts related to a relay. `tagCount[1]` is the value expressed as the string representation of an integer or float. `tagCount[2]` is the key and describes the count, such as `total_users` or `total_events`. Counts **should** only be included when representing unique or computationally expensive counts, not ones that can be easily achieved via NIP-XX counts, via NIP-XX searches or other filters. There **may** be **0** to **many** count tags.
["g","ww8p1r4t8","geohash"], ```
["g","NL","countryCode"], ["count", "total_events", "502341"],
["g","EU","continent"], ["count", "total_users", "52000"],
["g","Earth","planet"] ["count", "active_users_24h", "321"]
``` ["count", "events_per_minute", "21.4"]
5. `"read" == tagRead[0]` Was able to read from the relay. `tagRead[]` **may** be included in the `event.tags[]` array. `tagRead[1]` **must** be type string as exactly `true` or `false` ```
```json
["read", "true"] //tagRead[] - `"infohash" == tagInfohash[0]` A SHA256 hash of the deterministically stringified `NIP-11` "Info Document" JSON at `tagInfohash[1]`
```
6. `"write" == tagWrite[0]` Was able to write to the relay. `tagWrite[]` **may** be included in the `event.tags[]` array. `tagWrite[1]` **must** be type string as exactly `true` or `false` - `"notice" == tagNotice[0]` Special tag to display information about a relay. `tagNotice[1]` is a key to describe the notice. `tagNotice[2...]` **should** be the value(s) of the notice. There **may** be **0** to **many** notice tags.
```json
["write", "false"] //tagWrite[] - `"expiration" === tagE[0]` An expiration timestamp to forcefully limit retention of relay events [`NIP-40`]
```
7. `"ssl" == tagSsl[0]` Is the relay's SSL valid. `tagSsl[]` **may** be included in the `event.tags[]` array. `tagSsl[1]` **must** be type string as exactly `true` or `false` - `"e" === tagE[0]` An association to another standard nostr event (`1000-9999` kind-range). An example would be an event containing the most recent check log or an archival event representing the check. Such a reference may contain duplicate or ommitted tags from a `30066` event. The event referenced here **should** at a minimum be described in a draft NIP.
```json
["ssl", "true"] //tagSsl[] #### Label Tags <sup>NIP-32</sup>
```
8. `"ip" == tagIp[0]` Relay IP. `tagIp[]` **may** be included in the `event.tags[]` array. `tagIp[1]` **must** be string. There **may** be more than one (1) `tagIp[]`. - `network`: Such as `clearnet`, `tor`, `i2p`, `cjdns`, etc.
```json ```
["ip", "1.1.1.1"], //tagIp[] [ 'L', 'network' ]
["ip", "2001:db8:3333:4444:5555:6666:7777:8888"] //tagIp[] [ 'l', 'clearnet', 'network' ]
``` ```
9. `"events" == tagEvents[0]` Number of events on relay. `tagEvents[]` **may** be included in the `event.tags[]` array. `tagEvents[1]` **must** be string. There **should** be no more than **one (1)** `tagEvents[]`
```json - `relay_type`, for example `proxy`, `bridge` and `public` for example. There **may** be more than one type.
["events", "502341"], //tagEvents[] ```
``` [ 'L', 'relay_type' ]
10. `"users" == tagUsers[0]` Number of users on relay. `tagUsers[]` **may** be included in the `event.tags[]` array. `tagUsers[1]` **must** be string. There **should** be no more than **one (1)** `tagUsers[]` [ 'l', 'proxy', 'relay_type' ]
```json [ 'l', 'public', 'relay_type' ]
["users","37482"] //tagUsers[] ```
```
- `ipv4` and `ipv6`, relay ips.
```
[ 'L', 'ipv4' ]
[ 'l', '1.1.1.1', 'ipv4' ]
[ 'L', 'ipv6' ]
[ 'l', '2001:db8:3333:4444:5555:6666:7777:8888"', 'ipv6' ]
```
- Data from `NIP-11` using dot notation, for example
```
[ 'L', 'nip11.tags' ]
[ 'l', 'sfw-only' ]
[ 'l', 'bitcoin-only' ]
[ 'L', 'nip11.language_tags' ]
[ 'l', 'en', 'nip11.language_tags' ]
[ 'l', 'en-419', 'nip11.language_tags' ]
```
#### Topic Tags
`NIP-66` leverages topics [`t` tags] for enumeration of nip support and NIP-11 boolean values
- `supported_nips` from `NIP-11`, no leading zero.
```
[ 't', 'nip-1' ]
[ 't', 'nip-2' ]
[ 't', 'nip-9' ]
[ 't', 'nip-11' ]
```
- For example `payment_required` and `auth_required` from `NIP-11.limitations`
```
[ 't', 'payment_required' ]
[ 't', 'auth_required' ]
```
#### Methodology
A Checking Monitor publishes 30066 events exclusively when a relay is operational. This approach ensures that the last known state of the relay is maintained and recorded. Based on this data, several inferences can be drawn about the relay's status and characteristics
1. Clients and/or users can set a custom threshold to establish a cutoff timestamp for filtering events. This timestamp helps in identifying which relays are currently online. Selecting a lower threshold value results in a stricter criterion for relay uptime, making the filter more sensitive to brief downtimes. Conversely, choosing a higher threshold value creates a more lenient filter, allowing relays with longer downtimes to still be considered as online.
2. In determining whether a relay is 'dead,' the decision is solely at the discretion of the client or user. They are responsible for setting and applying arbitrary thresholds to make this determination. This approach underscores that the classification of a relay as 'dead' is a subjective decision, varying according to each client's or user's assessment criteria, rather than a fixed status provided by the monitor.
3. For relay status events that have become outdated, the retained data points remain valuable. They offer insights and information about the relay's characteristics and performance, which might not be currently accessible due to the relay being offline.
Example with Minimum Requirements, "Relay is online" #### Important Notes
- `NIP-11` values are provided as means to filter and discover relays, however **should not** be used as a replacement to `NIP-11`.
- A relay's retention policy could conflict with subjective thresholds used in determination of "online" or "dead" relays.
#### Examples
##### Minimum Requirements, "Relay was on a relay list"
```json ```json
{ {
"id": "<eventid>", "id": "<eventid>",
@ -73,53 +174,108 @@ Example with Minimum Requirements, "Relay is online"
"signature": "<signature>", "signature": "<signature>",
"content": "", "content": "",
"tags": [ "tags": [
["d","wss://relay.snort.social/"], ["d","wss://some.relay/"]
["expiration", "1600000000"]
] ]
} }
``` ```
Example with all Tags, "Relay is online and here's some data" ##### Minimum Requirements, "Relay was on a list but it might be a typo"
```json ```json
{ {
"id": "<eventid>", "id": "<eventid>",
"pubkey": "<pubkey>", "pubkey": "<pubkey>",
"created_at": "<created_at>", "created_at": "<created_at>",
"signature": "<signature>", "signature": "<signature>",
"content": "{}", "content": "",
"tags": [ "tags": [
["d","wss://some.relay/"], ["d","wdd://some.relay/"]
["expiration", "1600000000"], ["notice", "typo", "wss://some.relay/"]
["t","nostrica"],
["t","bitcoin"],
["g","ww8p1r4t8","geohash"],
["g","NL","countryCode"],
["g","EU","continent"],
["g","Earth","planet"],
["ip","1.1.1.1"],
["ip","2001:db8:3333:4444:5555:6666:7777:8888"],
["read","true"],
["write","false"],
["ssl","true"],
["events", "502341"],
["users","37482"]
] ]
} }
``` ```
### `event.content` _optional_ ##### Relay is checked and online example, "Relay is online and here's some meta-data this monitor believes is accurate"
The `.content` of these events **may** be empty. `.content` **may** contain stringified JSON. The parsed JSON has a flexible schema, all members are optional. The parsed `.content` JSON **should** be extended by NIPs. ```json
{
"id": "<eventid>",
"pubkey": "<monitor's pubkey>",
"created_at": "<created_at [some recent date ...]>",
"signature": "<signature>",
"content": "{}",
"tags": [
["d","wss://some.relay/"],
["rtt", "open", "201", "190", "540"],
["rtt", "read", "35", "60", "46"],
["rtt", "write", "701", "497", "508"],
["ssl", "valid", "timestamp", "timestamp"],
["count", "502341", "events"],
["count", "21.4", "events_per_minute"],
["L", "network"]
["l", "clearnet", "network"]
["g", "ww8p1r4t8","geohash"],
["g","NL","countryCode"],
["g","EU","continent"],
["g","Earth","planet"],
["L","ipv4"],
["l","1.1.1.1""ipv4" ],
["L","ipv6"],
["l","2001:db8:3333:4444:5555:6666:7777:8888","ipv6"],
["t", "nip-1"],
["t", "nip-7"]
]
}
```
## Testing Criteria ##### Relay was checked and has been online, "Relay was online at _some_ point..."
The testing criteria to determine conditions defined in event's tags **may** be subjective and **may** vary between publishers.
## Consumption ```json
The data in `30303` **may** be erroneous, intentionally or otherwise. Where accuracy is required, the data in `30303` events **should** be subscribed to by populating the `authors` filter array with the pubkeys of trusted **publishers**. **IP** data is for informational purposes only. {
"id": "<eventid>",
"pubkey": "<monitor's pubkey>",
"created_at": "<created_at [some date in the distant past...]>",
"signature": "<signature>",
"content": "",
"tags": [
["d","wss://some.relay/"],
["rtt", "open", "201", "190", "540"],
["rtt", "read", "35", "60", "46"],
["rtt", "write", "701", "497", "508"],
...
]
}
```
## Use Cases #### Testing Criteria
- Aggregate relays quickly using an implementation pattern native to nostr. The testing criteria to determine conditions defined in event's tags **may** be subjective and **may** vary between monitors.
- A lite social client identifies relays that were recently reported to be online without client-side tests
- A social client may find relays where a particular topic is popular. #### Limitations
- A social client may find relays based on their geographic proximity The data in `30066` **may** be erroneous, intentionally or otherwise. Where accuracy is required, the data in `30066` events **should** be subscribed to by populating the `authors` filter array with the pubkeys of trusted **monitors** and where security is a concern any republished values (such as NIP-11 values) should be attained from the source. All data is for informational purposes and to make finding and filtering through relays through nostr a possiblity.
- A status client shows relay statuses
- Relays self-report statuses and/or metadata in `.content` signed by their NIP-11 `pubkey`. #### Appending NIP-66
Any test results that cannot be expressed through `NIP-66` **should** be ammended to the nip following discussion and general consensus
### Use Cases
1. **Geographic Relay Discovery**: Identify relays situated near a specific geographic location or within a particular country, facilitating localized network interactions.
2. **NIP Support Filtering**: Search for relays based on their support for specific Nostr Improvement Proposals (NIPs), ensuring compatibility with desired protocol features.
3. **Accessibility Search**: Locate relays that are free to use, helping users find cost-effective or no-cost options for their network interactions.
4. **Real-Time Status Monitoring**: Utilize a status client to display up-to-date statuses of various relays, providing insights into their current operational state.
5. **Relay Network Analysis**: Analyze connections and patterns between relays using their IP addresses, aiding in network topology understanding and security assessments.
6. **Error Detection in Relay Listings**: Spot and rectify erroneous entries in relay lists, ensuring the accuracy and reliability of relay data.
7. **Performance Benchmarking**: Compare relays based on performance metrics like round-trip times and uptime, aiding in the selection of the most efficient relays for specific needs.
8. **Security and Compliance Checks**: Evaluate relays for adherence to security standards and regulatory compliance, essential for users with specific security and privacy requirements.
9. **Language and Content Filtering**: Identify relays catering to specific languages or content types, enabling users to engage in a more targeted and relevant social networking experience.
10. **Data-Driven Relay Selection**: Make informed choices about which relays to connect to, based on comprehensive metadata including user counts, event frequencies, and network types.
# Glossary
- `aggregate` the act of aggregating, qualifying, sanitizing and normalizing relays from relay lists to build a subjectively complete dataset of known relays.
- `check` the act of running tests on one or many attributes of a relay.