Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-34 - Algorithmic Filter #579

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
87 changes: 87 additions & 0 deletions 34.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
NIP-34
======

Algorithmic Filter
------------------

`draft` `optional` `author:arthurfranca`

This NIP introduces a set of simple algorithms meant to support diverse apps' event sorting needs.

`Relays` MUST store an extra event field for each algo. There are two algo event fields: `asc` and `seen_at`.

According to [NIP-01](01.md), filters with `limit` attribute are replied with events
sorted in **descending** order by the `created_at` event field (newest events first).

But now when a `client` requests events to be filtered by an algo field, the `relay` MUST replace the `created_at` field in the query with the algo field. For example, when filtering by the `asc`
algo, a SQL relay should turn this:

`SELECT * FROM events WHERE kind in (1) ORDER BY created_at DESC LIMIT 5`

Into this:

`SELECT * FROM events WHERE kind in (1) ORDER BY asc DESC LIMIT 5`

## Querying

An extra `algo` filter key holds the selected algorithm as value. For example, the above
query is ran in response to the following request:

`["REQ", <sub_id>, { kinds: [1], limit: 5, algo: "asc" }]`

Upon replying to such requests, the supporting `relay` MUST add an extra `score` field,
namespaced in an `algo` key, holding the selected algo's event field value. It must be
added to each returned event JSON.

The algo field is calculated as described in the [Algorithms](#algorithms) section below.

For example, considering above request, one of the events replied should be as follows:

```js
{
id: "...",
// ... (other regular event fields)
kind: 1,
algo: {
score: 1695408196 // the stored event.asc field value
}
}
```

## Algorithms

This section describes how the extra event field is calculated for each algo before saving it to the database.

### Ascending (asc)

`Relay` computes `asc` field once upon receiving the event. The lower the `created_at`, the higher `asc` will be.

```js
function getAsc (createdAt) {
const maxDateNowSeconds = 8640000000000 // 8.64e15 ms / 1000

// Make it lower the greater the ts is (the newer the createdAt is)
// maxDateNowSeconds - -maxDateNowSeconds equals 17280000000000 and is lower than Number.MAX_SAFE_INTEGER
return maxDateNowSeconds - createdAt
}
event.asc = getAsc(event.created_at)
```

### Seen At (seen_at)

`Relay` computes `seen_at` field once upon receiving the event. The event field is set with the timestamp of the moment the `relay` first became aware of it, in seconds.

```js
event.seen_at = Math.floor(Date.now() / 1000)
```

## Relay Connection URL Query Parameter

For each algorithm, the `relay` MUST allow `clients` to specify the algo as an `algo` query param on the connection URL string.

In other words, a `relay` whose regular URL is `wss://relay.url/r1` MUST also respond at `wss://relay.url/r1?algo=asc` and `wss://relay.url/r1?algo=seen_at`.

Then, for example, when `clients` connect to `wss://relay.url/r1?algo=asc` and request events using the `limit`
filter attribute, the relay will automatically sort events using the `asc` event field instead of the `created_at` one when replying.

Clients can still override the chosen algorithm if using the `algo` filter attribute on `REQ` messages.