-
Notifications
You must be signed in to change notification settings - Fork 751
Generalise event lifetime preferences #236
Description
Background
Implementing NIP-33 and NIP-40 for my relay (strfry) caused me to think a bit about user-specified event lifetime preferences. We can roughly classify these into the following categories:
- Replaceable events, including parameterised replaceable (NIP-16, NIP-33): These indicate to a relay that an event can be removed when another more recent qualifying event is received
- Ephemeral events (NIP-16): These events should be broadcast to all connected users with a matching filter, but then deleted (or not stored in the first place)
- Expiring events (NIP-40): These events should be deleted when a specifed timestamp is reached
Note that if a relay supports NIP-09 deletions then all of the above could in principle be implemented with delete events:
- Replaceable events could be deleted immediately before posting a replacing event
- Ephemeral events could be deleted immediately after posting
- Expiring events could be deleted at their expiration time
By using deletions, any of these categories of event lifetimes could be implemented for events of any kind.
Problems
Replaceable, parameterised replaceable, and ephemeral events are specified to only apply to events within ranges of kinds. To me this seems sub-optimal:
- Protocols can't group their kinds together if they need different event lifetimes for different kinds. For instance, NIP-28 (public chat) reserves the range of kinds 40-49 but specified kind 41 to be replaceable, before NIP-16 was specified, I assume. With NIP-16, a non-contiguous kind in the 10000-19999 range would need to be reserved.
- Kinds can't compose with event lifetimes. A new protocol might like to have some messages of the same kind have different event lifetimes. For example, a protocol might like to support editable (replaceable) postings as well as "permanent" postings using the same kind.
- Users can't specify custom lifetimes for events of existing protocols. For example, you could imagine sending an ephemeral kind 1 message, as a "disappearing" temporary message that would pretty much just work on any existing client.
- The 10k blocks of ranges are arbitrarily sized, and they could be either too small (new ranges would have to be reserved in the future) or too big (prime kind real-estate will forever go unused).
- Users who aren't aware of the special handling of a particular kind mind start using it and get unexpected event lifetimes.
Importance of parameterised replaceable events
I believe NIP-33 is a very important specification and will be heavily used by future protocols.
The NIP itself doesn't contain any use-cases, but as a basic example, I could imagine using these types of event lifetimes for sharding and segregating your kind-3 contact lists. You could imagine having multiple different contact lists, like family, friends, co-workers, randos1, and randos2. This would future-proof contact lists growing too large, improve the efficiency of updates, and provide a natural organisation schema for users.
Furthermore, if it were possible to use parameterised replaceable events on kind 3, this would all work with minimal client changes and a reasonable backwards compatibility story. I'm not saying this is a good idea and we should do it, just pointing out the possibility.
Note that replaceable events are just a special case of parameterised replaceable events with a static replacement key.
Proposal
Here are two minor changes that I believe would generalise the protocol:
- Extend NIP-40 to special-case an
expirationtag with value0. This would indicate that the event is intended to be ephemeral, and should be treated as described in NIP-16, regardless of kind. - Support the
dtag on events of any kind. This indicates the event is to be treated as a parameterised replaceable event as described in NIP-33, using the value of this tag as a replacement key. This works for any kind, but the kinds of the replaced and replacing events must still match. The absence of adtag does not result in an implicit emptydtag as described in NIP-33.
Disadvantages
- Events that want replaceable behaviour become slightly larger, since they need to include a
dtag. - A user could forget to include a
dtag and unintentionally have multiple events of the same kind on a relay. However, when querying, clients that expect replaceable behaviour could take care to select the latest one (bycreated_at). Additionally, the user could correct this situation using a NIP-09 deletion.
Back-compat
The two above changes would not break any of the existing NIPs. However, I think it could make sense to create a NIP that supersedes NIPs 16 and 33, and mark the coupling of event lifetime with the 10k kind-ranges deprecated.
Additionally, here is how a relay could internally implement backwards compatibility using the d and expiration primitives:
- Kinds 20000-29999 have an implicit
expirationtag with value0added to the front of the tag list. NIP-40 is clarified to specify that in the case of multipleexpirationtags, the first tag's value is to be used. - Kinds 0, 3, 41, 10000-19999, and 30000-39999 have implicit
"d"tags with""values added to the end of their tags list.
History
- The original version of this proposal suggested using a
replacetag instead of NIP-33'sdtag, but this would not have been queryable as pointed out by @barkyq below.